Глава 3. Организация проекта

В данной главе рассматривается три варианта организации проекта (дерева его папок). Для наиболее гибкого варианта мы создадим минимальный код проекта, скомпилируем и запустим его примеры и файл симуляции.

Организация проекта, зависит от уровня задачи, которую предстоит решать:

  1. уровень Быстрое тестирование

  2. уровень Серьезный проект

  3. уровень Исследование

Рассмотрим каждый из уровней по порядку.

1.1 Быстрое тестирование

Для проведения быстрого тестирования, изучения API или реализации небольших одноразовых экспериментов наиболее подходящей является директория scratch - папка внутри директории ns-3.45, где CMake по умолчанию осуществляет поиск и компиляцию ваших сценариев.

Плюсы:

  • Проста в использовании: пользователь создает C++-файл теста в директории scratch/ и запускает симуляцию командой: ./ns3 run my-test.

  • Не требует никакой дополнительной настройки, если вы разрабатываете примеры или тесты для какого-то модуля и располагаете их по правилам, т.е. внутри директории модуля, то каждый новый тест вам придется вручную прописывать в соответствующие CMake-файлы. В то время как в папке scratch это произойдет автоматом при запуске компиляции.

Минусы:

  • Отсутствие масштабирования: все ваши файлы «лежат в одной куче»;

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

  • Смешение логики: в одном файле смешаны и настройка топологии, и реализация нового приложения/протокола, и запуск симуляции.

Вывод: scratch — это «черновик», не подходящий для реализации серьезного проекта. Но если вы добавляете в ваш серьезный проект новы тест, то удобнее сналала его отладить в папке scratch, а затем перенести в проект уже работающий должным образом код.

1.2 Профессиональный подход

Профессиональны подход состоит в создании собственного модуля, что является правильным способом организации кода в NS-3. Мы инкапсулируем свою логику (новые приложения, протоколы, модели) в отдельный модуль, который имеет тот же вид, что и стандартные модули NS-3 (internet, wifi, point-to-point и т.д.).

Плюсы:

  • Код логично сгруппирован;

  • Имеется возможность использовать новый модуль в разных симуляционных сценариях;

  • Детали реализации скрыты от пользователя модуля, который работает с ним через простые Helper-классы;

  • Модуль становится частью системы сборки NS-3.

Минусы:

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

Как создать свой модуль?

Для этой цели в к NS-3 имеется специальная утилита: create-module.py. Переходим в корень директории ns-3.45:

$ cd ~/workspace_ns3.45/ns-allinone-3.45/ns-3.45 

Имя модуля может состоять из следующих символов: букв, цифр, символов “'-” и “_”. Запустим утилиту, предположим, что мы хотим создать модуль с именем my-new-module:

$ ./utils/create-module.py my-new-module

Утилита выводит примерно такой ответ:

$ Creating module ~/workspace_ns3.45/ns-allinone-3.45/ns-3.45/contrib/my-new-module
Successfully created new modules Run './ns3 configure' to include them in the build 

Эта команда создаст директорию contrib/my-new-module/ со структурой, показанной в листинге 1.1.

Листинг 1.1: Дерево файлов модуля

my_new_module
|-- CMakeLists.txt
|-- doc # Documentation (Doxygen)
|   `-- my-new-module.rst
|-- examples # Usage examples for your module
|   |-- CMakeLists.txt
|   `-- my-new-module-example.cc
|-- helper # Helper classes for simplifying setup
|   |-- my-new-module-helper.cc
|   `-- my-new-module-helper.h
|-- model # Main implementation of your classes
|   |     #     (applications, protocols) 
|   |---my-new-module.cc
|   `---my-new-module.h
`-- test # Unit tests for your code
    `---my-new-module-test-suite.cc

В директориях утилита также создаст файлы-заготовки, модуль сразу получается пригодным для компиляции.

Что где располагать

  • model/: Если моделируется новый модуль (например, протокол маршрутизации) MyNewModule, здесь располагаются my-new-module.cc и my-new-module.h.

  • helper/: Здесь располагаются my-new-module-helper.cc и my-new-model-helper.h. Этот класс помогает пользователям устанавливать протокол на узлы, выполнить настройки по умолчанию.

  • examples/: Небольшие сценарии-примеры, демонстрирующие, как использовать MyNewModuleHelper.

Если проект содержит несколько модулей, можно передать утилите название проекта, и она создаст в директории contrib директорию с именем проекта, а модули поместит уже в неё:

$ ./utils/create-module.py --project PROJECT module1 module2 module3 

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

$ ./utils/create-module.py -h 

Чтобы симулятор начал использовать новые модули (это же касается и тестов), после их создания необходимо вызвать команду:

$ ./ns3 configure --enable-examples --enable-tests

1.3 Большой проект

Когда у нас есть свой модуль, то сама симуляция (сценарий) — это всего лишь программа, использующая этот модуль. Поэтому лучше всего отделить код модуля от кода сценария. Наиболее гибким решением является вынос файлов модулей и симуляций за пределы кодовой базы симулятора. В листинге 1.2 показывается структура для большого исследовательского проекта:

Листинг 1.2: Дерево файлов большого проекта

big-ns3-project
|--- ns-3.45               # Link to the NS-3 source code
|    `--- contrib
|         `--- my-cool-protocol/  # Your custom module, created via
|                                 # the create-module.py utility
|--- simulations/             # <--- IMPORTANT: Your experiment scripts go here!
|--- results/                 # <--- Raw simulation results
|--- analysis/                # <--- Scripts for data processing and analysis
|---plots/                    # <--- Final plots and figures for publications
|---doc/                      # Project documentation
|   `-- project_description.md
|--- README.md               # Main project file: how to build and run
`---.gitignore               # Git ignore file

Для создания такого дерева проекта создана «питоновская» утилита create_ns_project, которую можно скачать с Github.com

Пример создания проекта

Создание директории внешних модулей

В симуляторе NS-3 действует соглашение, согласно которому, исходный код внешних модулей должен располагаться в директории с названием ns-3-external-contrib*. Она, в свою очередь, должна располагаться на одном уровне с директорией ns3.45. Создаем директорию внешних модулей командой:

$ mkdir ~/workspace_ns3.45/ns-allinone-3.45/ns-3-external-contrib

Создание дерева проекта

Далее создаем дерево проекта. Для этого запускаем утилиту create_ns_project, передав ей в качестве аргументов название проекта и путь к папке внешних модулей. Пусть наш проект будет иметь название «my_project»:

$ python ./create_ns_project.py -p my_project -o ~/workspace_ns3.45/ns-allinone-3.45/ns-3-external-contrib

В случае успеха выводится сообщение:

 Project 'my_project' created successfully!
 Navigate to the directory: cd /home/igor/workspace_ns3.45/ns-allinone-3.45/ns-3-external-contrib/my_project
 Read README.md for instructions on integrating with NS-3.

В результате работы утилиты в директории ns-3-external-contrib создается проект с именем my_project.

Создание символической ссылки на директорию ns3.45

Для удобства работы с утилитами находящимися в папке симулятора, создадим внутри проекта символическую ссылку на эту папку:

$ ln -s ~/workspace_ns3.45/ns-allinone-3.45/ns-3.45 ~/workspace_ns3.45/ns-allinone-3.45/ns-3-external-contrib/my_project/ns-3.45

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

Переходим в папку проекта:

$ cd  ~/workspace_ns3.45/ns-allinone-3.45/ns-3-external-contrib/my_project

Предположим, что необходимо создать модуль my_module. Тогда вызов утилиты create-module имеет вид:

$ ./ns-3.45/utils/create-module.py my_module  

В случае успеха выводится сообщение:

Creating module /home/igor/workspace_ns3.45/ns-allinone-3.45/ns-3-external-contrib/my_project/contrib/my_module

Successfully created new modules
Run './ns3 configure' to include them in the build

В папке contrib появляется дерево папок модуля my_module со всеми необходимыми для сборки модуля файлами.

Добавление в проект основного файла CMakeLists.txt

Добавляем в корневой каталог проекта файл CMakeLists.txt со следующим содержанием:

cmake_minimum_required(VERSION 3.10)
project(MyProject)

add_subdirectory(contrib)

Добавление файла CMakeLists.txt в директорию contrib

Добавляем в директорию contrib файл CMakeLists.txt со следующим содержанием:

add_subdirectory(my_module)

В данный момент файл содержит ссылку на директорию модуля. При добавлении в проект новых модулей, ссылки на их директории также необходимо добавить в этот файл.

Сборка и запуск примера использования модуля my_module

Выполняем конфигурирование сборки файлов:

$ ./ns3 configure --enable-examples --enable-tests  

Выполняем сборку модулей и файлов симуляции:

$ ./ns3 build  

Если сборка проходит без ошибок, то в списке целей сборки, который можно получить командой:

$  ./ns3 show targets 

появляется цель, соответствующая нашему модулю, с именем my_module-example, эту цель необходимо использовать для запуска примера симуляции:

$ ./ns3 run my_module-example  

В ответ мы получаем сообщение:

[0/2] Re-checking globbed directories...
ninja: no work to do.

Так как файл примера создан автоматически - в нем еще нет полезного функционала, результат симуляции содержит только эти две строчки.

Сборка и моделирование проекта

Создаем в директории simulations сценарий my_project-simulation.cc, со следующим содержанием:

// simulations/my_project-simulation.cc

#include "ns3/core-module.h"
#include "ns3/my_module-helper.h"

/**
 * @file
 *
 * Explain here what the example does.
 */

using namespace ns3;

int
main(int argc, char* argv[])
{
    bool verbose = true;

    CommandLine cmd(__FILE__);
    cmd.AddValue("verbose", "Tell application to log if true", verbose);

    cmd.Parse(argc, argv);

    /* ... */
    NS_LOG_UNCOND("My Project simulation Hello");   
    Simulator::Run();
    Simulator::Destroy();
    return 0;
}

В отличие от файлов по умолчанию, при запуске этот файл выводит сообщение «My Project simulation Hello». В этом мы убедимся ниже, запустив симуляцию. Добавляем в эту же директорию файл CMakeLists.txt со следующим содержанием:

# simulations/CMakeLists.txt

# Create an executable for our simulation
add_executable(my_project-simulation my_project-simulation.cc)

# Specify the libraries to link against
target_link_libraries(my_project-simulation
  core
  network
  my_module
)


# Define the path to the build directory
set(BUILD_DIR ${CMAKE_SOURCE_DIR}/build)

# Create the simulation directory inside the build directory
file(MAKE_DIRECTORY ${BUILD_DIR}/simulation)

# Set the output directory to build/simulation
set_target_properties(my_project-simulation PROPERTIES
  RUNTIME_OUTPUT_DIRECTORY ${BUILD_DIR}/simulation
)

Изменяем файл CMakeLists.txt в корневом каталоге проекта, дополнив его строчкой add_subdirectory(simulations), теперь он будет выглядеть так:

# my_project/CMakeLists.txt

cmake_minimum_required(VERSION 3.10)
project(MyProject)


add_subdirectory(contrib)
add_subdirectory(simulations)

Выполняем конфигурирование сборки файлов:

$ ./ns3 configure --enable-examples --enable-tests  

Выполняем сборку модулей и файлов симуляции:

$ ./ns3 build  

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

$  ./ns3 show targets 

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

$ ./ns3 run my_module-example  

Вместо этого осуществляем прямой запуск исполняемого файла:

$ ./build/simulation/my_project-simulation  

Во время выполнения симуляция выведет сообщение:

My Project simulation Hello

После добавления необходимых файлов дерево проекта принимает следующий вид:

Листинг 1.3: Итоговое дерево файлов проекта

my-project
|-- about_folder.md
|-- analysis
|   `-- about_folder.md
|-- CMakeLists.txt
|-- contrib
|   |-- about_folder.md
|   |-- CMakeLists.txt
|   `-- my_module
|       |-- CMakeLists.txt
|       |-- doc
|       |   `-- my_module.rst
|       |-- examples
|       |   |-- CMakeLists.txt
|       |   `-- my_module-example.cc
|       |-- helper
|       |   |-- my_module-helper.cc
|       |   `-- my_module-helper.h
|       |-- model
|       |   |-- my_module.cc
|       |   `-- my_module.h
|       `-- test
|           `-- my_module-test-suite.cc
|-- doc
|   `-- about_folder.md
|-- plots
|   `-- about_folder.md
|-- README.md
|-- results
|   `-- about_folder.md
|-- simulations
|   |-- about_folder.md
|   |-- CMakeLists.txt
|   `-- my_project-simulation.cc
`-- src
    `-- about_folder.md

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

Мы рассмотрели способы организации проекта, их преимущества и недостатки. На сегодня это всё. В следующей статье мы приступим к изучению модуля спутниковой связи Satellite.

Работа выполнена в рамках Программы создания и развития центра НТИ на базе МФТИ, Физтех по направлению («сквозной» технологии) Национальной технологической инициативы «Перспективные технологии для космических систем и сервисов» при реализации комплексного научно-исследовательского и опытно-конструкторского проекта “Разработка комплексной среды моделирования и проектирования гибридных инфокоммуникационных сетей наземного, стратосферного и космического сегментов с использованием параметрического и структурного синтеза”.

Комментарии (0)