├── .github ├── ISSUE_TEMPLATE │ └── subscription-request-template.md └── workflows │ ├── ci.yml │ └── cmake-single-platform.yml ├── .gitignore ├── CMakeLists.txt ├── LICENSE ├── README.md ├── docs ├── Installation.md ├── algorithms │ └── decision-engines.md ├── assets │ └── logo.png ├── index.md ├── misc.md ├── network │ └── network-models.md ├── okec │ ├── components │ │ └── common │ │ │ ├── simulation-time.md │ │ │ ├── simulator.md │ │ │ ├── simulator │ │ │ ├── compele.md │ │ │ ├── hold_coro.md │ │ │ ├── is_valid.md │ │ │ ├── run.md │ │ │ ├── simulator.md │ │ │ ├── stop_time.md │ │ │ ├── submit.md │ │ │ └── ~simulator.md │ │ │ ├── task.md │ │ │ └── task │ │ │ └── task.md │ ├── customization │ │ ├── decision-engines.md │ │ ├── network-models.md │ │ ├── resources.md │ │ ├── responses.md │ │ └── tasks.md │ └── getting-started │ │ ├── formatting.md │ │ ├── heterogeneous-devices.md │ │ ├── log.md │ │ ├── task-offloading.md │ │ ├── task.md │ │ └── visualizer.md ├── page2.md └── stylesheets │ └── extra.css ├── examples ├── CMakeLists.txt ├── scene2-rf-resource_tracer.csv └── src │ ├── fifth.cc │ ├── rf_discrete.cc │ ├── seventh.cc │ ├── sixth.cc │ ├── wf_async.cc │ ├── wf_discrete.cc │ └── wf_net.cc ├── images ├── discretely-offload-the-task-using-the-dqn-decision-engine.png ├── log.png ├── network-model-1.jpg ├── network-model-2.jpg ├── network-model-3.jpg ├── offloading-your-first-set-of-tasks-using-the-worst-fit-decision-engine.png ├── okec.jpeg ├── response-visualization-demo.png └── response-visualizer.png ├── include └── okec │ ├── algorithms │ ├── classic │ │ ├── cloud_edge_end_default_decision_engine.h │ │ └── worst_fit_decision_engine.h │ ├── decision_engine.h │ └── machine_learning │ │ ├── DQN_decision_engine.h │ │ └── RL_brain.hpp │ ├── common │ ├── awaitable.h │ ├── message.h │ ├── message_handler.hpp │ ├── resource.h │ ├── response.h │ ├── simulator.h │ └── task.h │ ├── config │ └── config.h │ ├── devices │ ├── base_station.h │ ├── client_device.h │ ├── cloud_server.h │ └── edge_device.h │ ├── mobility │ ├── ap_sta_mobility.hpp │ └── mobility.hpp │ ├── network │ ├── cloud_edge_end_model.hpp │ ├── multiple_LAN_WLAN_network_model.hpp │ ├── multiple_and_single_LAN_WLAN_network_model.hpp │ ├── network_model.hpp │ └── udp_application.h │ ├── okec.hpp │ └── utils │ ├── color.h │ ├── delegate.hpp │ ├── format_helper.hpp │ ├── log.h │ ├── message_helper.hpp │ ├── packet_helper.h │ ├── random.hpp │ ├── read_csv.h │ ├── singleton.hpp │ ├── sys.h │ └── visualizer.hpp ├── mkdocs.yml ├── okec-config.cmake.in └── src ├── algorithms ├── classic │ ├── cloud_edge_end_default_decision_engine.cc │ └── worst_fit_decision_engine.cc ├── decision_engine.cc └── maching_learning │ └── DQN_decision_engine.cc ├── common ├── awaitable.cc ├── message.cc ├── resource.cc ├── response.cc ├── simulator.cc └── task.cc ├── devices ├── base_station.cc ├── client_device.cc ├── cloud_server.cc └── edge_device.cc ├── network └── udp_application.cc └── utils ├── packet_helper.cc ├── read_csv.cc └── sys.cc /.github/ISSUE_TEMPLATE/subscription-request-template.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Subscription Request template 3 | about: Subscribe to receive updates and notifications 4 | title: Subscription Request 5 | labels: subscription 6 | assignees: lkimuk 7 | 8 | --- 9 | 10 | --- 11 | name: Subscription Request 12 | about: Subscribe to receive updates and notifications 13 | labels: [subscription] 14 | --- 15 | 16 | 17 | **Email Address:** [Your Email Address] 18 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: ci 2 | on: 3 | push: 4 | branches: 5 | - main 6 | permissions: 7 | contents: write 8 | jobs: 9 | deploy: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - uses: actions/checkout@v3 13 | - uses: actions/setup-python@v4 14 | with: 15 | python-version: 3.x 16 | - uses: actions/cache@v2 17 | with: 18 | key: ${{ github.ref }} 19 | path: .cache 20 | - run: pip install mkdocs-material 21 | - run: mkdocs gh-deploy --force 22 | -------------------------------------------------------------------------------- /.github/workflows/cmake-single-platform.yml: -------------------------------------------------------------------------------- 1 | # This starter workflow is for a CMake project running on a single platform. There is a different starter workflow if you need cross-platform coverage. 2 | # See: https://github.com/actions/starter-workflows/blob/main/ci/cmake-multi-platform.yml 3 | name: linux 4 | 5 | on: 6 | push: 7 | branches: [ "main" ] 8 | pull_request: 9 | branches: [ "main" ] 10 | 11 | env: 12 | # Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.) 13 | BUILD_TYPE: Release 14 | # CC: gcc-13 15 | # CXX: g++-13 16 | 17 | jobs: 18 | build: 19 | # The CMake configure and build commands are platform agnostic and should work equally well on Windows or Mac. 20 | # You can convert this to a matrix build if you need cross-platform coverage. 21 | # See: https://docs.github.com/en/free-pro-team@latest/actions/learn-github-actions/managing-complex-workflows#using-a-build-matrix 22 | runs-on: ubuntu-24.04 23 | 24 | steps: 25 | - uses: actions/checkout@v4 26 | 27 | # Step to cache downloaded dependencies 28 | - name: Cache dependencies 29 | uses: actions/cache@v2 30 | with: 31 | path: | 32 | ${{github.workspace}}/installed/libtorch 33 | ${{github.workspace}}/installed/fmtlib 34 | ${{github.workspace}}/installed/nlohmann 35 | ${{github.workspace}}/installed/ns3 36 | key: ${{ runner.os }}-build-${{ hashFiles('**/CMakeLists.txt') }} 37 | restore-keys: | 38 | ${{ runner.os }}-build- 39 | 40 | - name: Install python dev 41 | run: | 42 | sudo apt-get install python3-matplotlib python3-numpy python3-dev 43 | 44 | # - name: Install Matplotlib-cpp 45 | # if: steps.cache.outputs.cache-hit != 'true' 46 | # run: | 47 | # git clone https://github.com/lava/matplotlib-cpp.git libraries/matplotlib-cpp 48 | # cd libraries/matplotlib-cpp 49 | # mkdir build && cd build 50 | # cmake .. 51 | # sudo make install 52 | 53 | - name: Check if LibTorch exists 54 | id: check_libtorch 55 | run: | 56 | if [ -d "${{github.workspace}}/installed/libtorch" ]; then 57 | echo "LIBTORCH_EXISTS=true" >> $GITHUB_ENV 58 | fi 59 | 60 | - name: Check if nlohmann json exists 61 | id: check_nlohmann 62 | run: | 63 | if [ -d "${{github.workspace}}/installed/nlohmann" ]; then 64 | echo "NLOHMANN_EXISTS=true" >> $GITHUB_ENV 65 | fi 66 | 67 | - name: Check if ns3 exists 68 | id: check_ns3 69 | run: | 70 | if [ -d "${{github.workspace}}/installed/ns3" ]; then 71 | echo "NS3_EXISTS=true" >> $GITHUB_ENV 72 | fi 73 | 74 | - name: Install LibTorch 75 | if: steps.cache.outputs.cache-hit != 'true' && !contains(env.LIBTORCH_EXISTS, 'true') 76 | run: | 77 | curl -LO https://download.pytorch.org/libtorch/cpu/libtorch-cxx11-abi-shared-with-deps-2.3.0%2Bcpu.zip 78 | unzip libtorch-cxx11-abi-shared-with-deps-2.3.0%2Bcpu.zip -d ${{github.workspace}}/installed 79 | 80 | - name: Install nlohmann json 81 | if: steps.cache.outputs.cache-hit != 'true' && env.NLOHMANN_EXISTS != 'true' 82 | run: | 83 | git clone https://github.com/nlohmann/json.git libraries/nlohmann 84 | cd libraries/nlohmann 85 | cmake -S . -B build 86 | cmake --build ./build 87 | cmake --install ./build --prefix=${{github.workspace}}/installed/nlohmann 88 | 89 | - name: Install ns3 90 | if: steps.cache.outputs.cache-hit != 'true' && env.NS3_EXISTS != 'true' 91 | run: | 92 | wget https://www.nsnam.org/releases/ns-allinone-3.41.tar.bz2 93 | tar xfj ns-allinone-3.41.tar.bz2 94 | cd ns-allinone-3.41/ns-3.41 95 | ./ns3 configure --enable-examples --enable-tests --cxx-standard=23 --prefix=${{github.workspace}}/installed/ns3 96 | ./ns3 build 97 | ./ns3 install 98 | 99 | - name: Configure CMake 100 | # Configure CMake in a 'build' subdirectory. `CMAKE_BUILD_TYPE` is only required if you are using a single-configuration generator such as make. 101 | # See https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html?highlight=cmake_build_type 102 | run: cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DCMAKE_PREFIX_PATH="${{github.workspace}}/installed/libtorch;${{github.workspace}}/installed/ns3;${{github.workspace}}/installed/fmtlib;${{github.workspace}}/installed/nlohmann" 103 | 104 | - name: Build 105 | # Build your program with the given configuration 106 | run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} 107 | 108 | - name: Test 109 | working-directory: ${{github.workspace}}/build 110 | # Execute tests defined by the CMake configuration. 111 | # See https://cmake.org/cmake/help/latest/manual/ctest.1.html for more detail 112 | run: ctest -C ${{env.BUILD_TYPE}} 113 | 114 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Compiled Object files 5 | *.slo 6 | *.lo 7 | *.o 8 | *.obj 9 | 10 | # Precompiled Headers 11 | *.gch 12 | *.pch 13 | 14 | # Compiled Dynamic libraries 15 | *.so 16 | *.dylib 17 | *.dll 18 | 19 | # Fortran module files 20 | *.mod 21 | *.smod 22 | 23 | # Compiled Static libraries 24 | *.lai 25 | *.la 26 | *.a 27 | *.lib 28 | 29 | # Executables 30 | *.exe 31 | *.out 32 | *.app 33 | 34 | # Build 35 | build/ 36 | 37 | # vscode 38 | .vscode/ 39 | .VSCodeCounter/ 40 | 41 | # Runtime data files 42 | /examples/data/ 43 | 44 | # Temporary files 45 | temp/ 46 | temp*.cc 47 | *temp.cc 48 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright(c) 2023-2024 Gaoxing Li Distributed under the Apache License 2.0 (http://www.apache.org/licenses/) 2 | 3 | cmake_minimum_required(VERSION 3.12) 4 | 5 | # --------------------------------------------------------------------------------------- 6 | # Start okec project 7 | # --------------------------------------------------------------------------------------- 8 | project( 9 | okec 10 | VERSION 1.0.1 11 | DESCRIPTION "An edge computing simulator" 12 | LANGUAGES CXX 13 | ) 14 | 15 | message("\ 16 | __ __ _ ____ ___ \n\ 17 | / \\( / )( __)/ __) OKEC(a.k.a. EdgeSim++)\n\ 18 | ( O )) ( ) _)( (__ version ${PROJECT_VERSION}\n\ 19 | \\__/(__\\_)(____)\\___) https://github.com/dxnu/okec\n\ 20 | ") 21 | 22 | # Find the dependencies 23 | find_package(Torch REQUIRED) 24 | find_package(nlohmann_json REQUIRED) 25 | find_package(ns3 3.41 COMPONENTS libcore REQUIRED) 26 | find_package(PythonLibs REQUIRED) 27 | 28 | # message(${TORCH_CXX_FLAGS}) 29 | message("Welcome to the installation wizard for OKEC") 30 | message(STATUS "Found Torch: ${TORCH_FOUND}") 31 | message(STATUS "Found nlohmann_json: ${nlohmann_json_FOUND}") 32 | message(STATUS "Found ns3: ${ns3_FOUND}") 33 | message(STATUS "Found python libs: ${PYTHON_INCLUDE_DIRS}") 34 | 35 | # Found all source files 36 | file(GLOB_RECURSE SOURCE_FILES "${PROJECT_SOURCE_DIR}/src/*.cc") 37 | list(LENGTH SOURCE_FILES SRC_FILES_SIZE) 38 | message(STATUS "Found ${SRC_FILES_SIZE} source files of okec") 39 | # foreach(source_file ${SOURCE_FILES}) 40 | # message(STATUS " ${source_file}") 41 | # endforeach() 42 | 43 | # Define a shared library target named `okec` 44 | add_library(okec SHARED) 45 | 46 | target_sources(okec PRIVATE ${SOURCE_FILES}) 47 | 48 | target_include_directories(okec PUBLIC 49 | $ 50 | $ 51 | ${PYTHON_INCLUDE_DIRS} 52 | ) 53 | 54 | 55 | target_link_libraries(okec PUBLIC 56 | ${TORCH_LIBRARIES} 57 | ${PYTHON_LIBRARIES} 58 | nlohmann_json::nlohmann_json 59 | ns3::libcore ns3::libinternet ns3::libpoint-to-point ns3::libcsma ns3::libwifi 60 | ) 61 | 62 | target_compile_options(okec PRIVATE -Wall -Werror) 63 | target_compile_features(okec PUBLIC cxx_std_23) 64 | 65 | include(GNUInstallDirs) 66 | 67 | install(TARGETS okec 68 | EXPORT okec-targets 69 | ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} 70 | LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} 71 | INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} 72 | ) 73 | 74 | install( 75 | DIRECTORY ${PROJECT_SOURCE_DIR}/include/ 76 | DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} 77 | ) 78 | 79 | install(EXPORT okec-targets 80 | NAMESPACE okec:: 81 | DESTINATION ${CMAKE_INSTALL_LIBDIR}/okec/cmake 82 | ) 83 | 84 | include(CMakePackageConfigHelpers) 85 | set(LIB_INSTALL_DIR ${CMAKE_INSTALL_LIBDIR}/okec) 86 | configure_package_config_file( 87 | ${CMAKE_CURRENT_SOURCE_DIR}/okec-config.cmake.in 88 | "${CMAKE_CURRENT_BINARY_DIR}/okec-config.cmake" 89 | INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/okec/cmake 90 | PATH_VARS LIB_INSTALL_DIR 91 | ) 92 | 93 | file(APPEND "${CMAKE_CURRENT_BINARY_DIR}/okec-config.cmake" 94 | "include(CMakeFindDependencyMacro)\nfind_dependency(nlohmann_json)\nfind_dependency(ns3)\nlist(APPEND CMAKE_PREFIX_PATH ${CMAKE_PREFIX_PATH})\nfind_package(Torch)" 95 | ) 96 | 97 | install(FILES "${CMAKE_CURRENT_BINARY_DIR}/okec-config.cmake" 98 | DESTINATION ${CMAKE_INSTALL_LIBDIR}/okec/cmake 99 | ) 100 | 101 | write_basic_package_version_file( 102 | "okec-config-version.cmake" 103 | COMPATIBILITY SameMajorVersion 104 | ) 105 | 106 | install(FILES 107 | "${CMAKE_CURRENT_BINARY_DIR}/okec-config-version.cmake" 108 | DESTINATION ${CMAKE_INSTALL_LIBDIR}/okec/cmake 109 | ) -------------------------------------------------------------------------------- /docs/Installation.md: -------------------------------------------------------------------------------- 1 | #Installation 2 | ## Prerequisites 3 | 4 | |Library|Version|Compiler|Version|Language|Version| 5 | |---|---|---|---|---|---| 6 | |[**NS-3**](https://www.nsnam.org/releases/ns-3-41/)|3.41|**GCC**|13.0 above|**C++**|23 above| 7 | |[**libtorch**](https://pytorch.org/)|cxx11 ABI|**Clang**|N/A||| 8 | |[**nlohmann\_json**](https://github.com/nlohmann/json)|N/A|**MSVC**|19.34 above||| 9 | |[**matplotlib-cpp**](https://github.com/lava/matplotlib-cpp)|N/A||||| 10 | 11 | ## Install 12 | 13 | ```console 14 | $ git clone https://github.com/lkimuk/okec.git 15 | $ cd okec 16 | $ cmake -S . -B build -DCMAKE_PREFIX_PATH:STRING=/absolute/path/to/your/libtorch 17 | $ cmake --build build 18 | $ cmake --install ./build 19 | ``` 20 | 21 | If your prerequisite libraries are not installed in standard directories, you may need to specify multiple paths as follows: 22 | 23 | ```console hl_lines="3" 24 | $ git clone https://github.com/lkimuk/okec.git 25 | $ cd okec 26 | $ cmake -S . -B build -DCMAKE_PREFIX_PATH:STRING="/absolute/path/to/your/libtorch;/absolute/path/to/your/other/libraries" 27 | $ cmake --build build 28 | $ cmake --install ./build 29 | ``` 30 | 31 | ## Run examples 32 | 33 | ```console 34 | $ cd examples 35 | $ cmake -S . -B build 36 | $ cmake --build build 37 | $ ./wf-async 38 | $ ./wf_discrete 39 | $ ./wf_net 40 | $ ./rf_discrete 41 | ``` -------------------------------------------------------------------------------- /docs/algorithms/decision-engines.md: -------------------------------------------------------------------------------- 1 | # Decision Engines 2 | 3 | ## WF_decision_engine 4 | A decision engine implements the Worst-Fit algorithm. 5 | 6 | ### Examples 7 | 8 | ```cpp 9 | #include 10 | 11 | namespace olog = okec::log; 12 | 13 | void generate_task(okec::task& t, int number, std::string const& group) 14 | { 15 | for (auto i = number; i-- > 0;) 16 | { 17 | t.emplace_back({ 18 | { "task_id", okec::task::unique_id() }, 19 | { "group", group }, 20 | { "cpu", okec::rand_range(0.2, 1.2).to_string() }, 21 | { "deadline", okec::rand_range(1, 5).to_string() }, 22 | }); 23 | } 24 | } 25 | 26 | okec::awaitable offloading(auto user, okec::task t) { 27 | olog::debug("offloading begin"); 28 | 29 | co_await user->async_send(std::move(t)); 30 | auto resp = co_await user->async_read(); 31 | olog::success("received response."); 32 | 33 | okec::print("{:r}", resp); 34 | } 35 | 36 | int main() 37 | { 38 | olog::set_level(olog::level::all); 39 | okec::simulator sim; 40 | 41 | // Create 1 base station 42 | okec::base_station_container base_stations(sim, 1); 43 | // Create 5 edge servers 44 | okec::edge_device_container edge_servers(sim, 5); 45 | // Create 2 user devices 46 | okec::client_device_container user_devices(sim, 2); 47 | 48 | // Connect the base stations and edge servers 49 | base_stations.connect_device(edge_servers); 50 | 51 | // Set the network model for every device 52 | okec::multiple_and_single_LAN_WLAN_network_model model; 53 | okec::network_initializer(model, user_devices, base_stations.get(0)); 54 | 55 | // Initialize the resources for each edge server. 56 | okec::resource_container resources(edge_servers.size()); 57 | resources.initialize([](auto res) { 58 | res->attribute("cpu", okec::rand_range(2.1, 2.2).to_string()); 59 | }); 60 | 61 | // Install each resource on each edge server. 62 | edge_servers.install_resources(resources); 63 | 64 | // Specify the default offloading strategy 65 | auto decision_engine = std::make_shared(&user_devices, &base_stations); 66 | decision_engine->initialize(); 67 | 68 | 69 | // Offload tasks 70 | okec::task t; 71 | generate_task(t, 5, "1st"); 72 | auto user1 = user_devices.get_device(0); 73 | co_spawn(sim, offloading(user1, t)); 74 | 75 | 76 | // Run the simulator 77 | sim.run(); 78 | } 79 | ``` 80 | 81 | The output would be: 82 | 83 | ![WF-OUTPUT](https://github.com/okecsim/okec/raw/main/images/offloading-your-first-set-of-tasks-using-the-worst-fit-decision-engine.png) 84 | 85 | ## DQN_decision_engine 86 | A decision engine implements the Deep Q-Network (DQN) algorithm. 87 | 88 | ### Examples 89 | 90 | ```cpp 91 | #include 92 | 93 | namespace olog = okec::log; 94 | 95 | 96 | void generate_task(okec::task& t, int number, std::string const& group) 97 | { 98 | for (auto i = number; i-- > 0;) 99 | { 100 | t.emplace_back({ 101 | { "task_id", okec::task::unique_id() }, 102 | { "group", group }, 103 | { "cpu", okec::rand_range(0.2, 1.2).to_string() }, 104 | { "deadline", okec::rand_range(1, 5).to_string() }, 105 | }); 106 | } 107 | } 108 | 109 | 110 | int main() 111 | { 112 | olog::set_level(olog::level::all); 113 | okec::simulator sim; 114 | 115 | // Create 1 base station 116 | okec::base_station_container base_stations(sim, 1); 117 | // Create 5 edge servers 118 | okec::edge_device_container edge_servers(sim, 5); 119 | // Create 2 user devices 120 | okec::client_device_container user_devices(sim, 2); 121 | 122 | // Connect the base stations and edge servers 123 | base_stations.connect_device(edge_servers); 124 | 125 | // Set the network model for every device 126 | okec::multiple_and_single_LAN_WLAN_network_model model; 127 | okec::network_initializer(model, user_devices, base_stations.get(0)); 128 | 129 | // Initialize the resources for each edge server. 130 | okec::resource_container resources(edge_servers.size()); 131 | resources.initialize([](auto res) { 132 | res->attribute("cpu", okec::rand_range(2.1, 2.2).to_string()); 133 | }); 134 | 135 | // Install each resource on each edge server. 136 | edge_servers.install_resources(resources); 137 | 138 | // Specify the default offloading strategy 139 | auto decision_engine = std::make_shared(&user_devices, &base_stations); 140 | decision_engine->initialize(); 141 | 142 | 143 | // Discretely offload the task using the DQN decision engine. 144 | okec::task t; 145 | generate_task(t, 5, "1st"); 146 | int episode = 5; 147 | decision_engine->train(t, episode); 148 | 149 | 150 | // Run the simulator 151 | sim.run(); 152 | } 153 | ``` 154 | 155 | The output would be: 156 | 157 | ![DQN-OUTPUT](https://github.com/okecsim/okec/raw/main/images/discretely-offload-the-task-using-the-dqn-decision-engine.png) 158 | 159 | ## cloud_edge_end_default_decision_engine 160 | A decision engine that implements the Worst-Fit algorithm for cloud-edge-end scenarios -------------------------------------------------------------------------------- /docs/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dxnu/okec/72d45b5395ad7932a06c2d2bd9acc1957f854aa9/docs/assets/logo.png -------------------------------------------------------------------------------- /docs/index.md: -------------------------------------------------------------------------------- 1 | # Homepage 2 | 3 | ![OKEC](https://github.com/okecsim/okec/raw/main/images/okec.jpeg) 4 | 5 |

6 |

OKEC(a.k.a. EdgeSim++)

7 |
A Realistic, Versatile, and Easily Customizable Edge Computing Simulator
8 |

9 | 10 | [![Build status](https://ci.appveyor.com/api/projects/status/8b08rootot5dfrh2?svg=true)](https://ci.appveyor.com/project/lkimuk/okec) 11 | [![License](https://img.shields.io/github/license/lkimuk/okec.svg)](https://github.com/lkimuk/okec/blob/main/LICENSE) 12 | [![Codacy Badge](https://app.codacy.com/project/badge/Grade/5b7112a2f3be475a86eeb6247bbb864c)](https://app.codacy.com/gh/lkimuk/okec/dashboard?utm_source=gh&utm_medium=referral&utm_content=&utm_campaign=Badge_grade) 13 | ![Language](https://img.shields.io/github/languages/top/lkimuk/okec.svg) 14 | ![Last commit](https://img.shields.io/github/last-commit/lkimuk/okec.svg) 15 | [![Average time to resolve an issue](http://isitmaintained.com/badge/resolution/lkimuk/okec.svg)](http://isitmaintained.com/project/lkimuk/okec "Average time to resolve an issue") 16 | [![Percentage of issues still open](http://isitmaintained.com/badge/open/lkimuk/okec.svg)](http://isitmaintained.com/project/lkimuk/okec "Percentage of issues still open") 17 | 18 | Welcome to the OKEC (a.k.a EdgeSim++) homepage, a realistic, versatile, and easily customizable edge computing simulator. 19 | 20 | 86 | -------------------------------------------------------------------------------- /docs/misc.md: -------------------------------------------------------------------------------- 1 | # Miscellaneous -------------------------------------------------------------------------------- /docs/network/network-models.md: -------------------------------------------------------------------------------- 1 | # Network Models 2 | 3 | ## single_ap_clients_model 4 | The model sets up scenarios with a single base station serving clients from the same network segments. 5 | 6 | ![](https://github.com/okecsim/okec/blob/new/images/network-model-1.jpg?raw=true) 7 | 8 | ## multiple_aps_clients_model 9 | The model sets up scenarios with multiple base stations serving clients from different network segments. 10 | 11 | ![](https://github.com/okecsim/okec/blob/new/images/network-model-2.jpg?raw=true) 12 | 13 | ## cloud_edge_end_model 14 | The model constructs a cloud-edge-end scenario that includes multiple user devices, base stations, edge servers, and a cloud server. 15 | 16 | ![](https://github.com/okecsim/okec/blob/new/images/network-model-3.jpg?raw=true) 17 | 18 | ## simple_edge_model 19 | The model constructs a simple, pure edge computing scenario that includes user devices and several edge servers. -------------------------------------------------------------------------------- /docs/okec/components/common/simulation-time.md: -------------------------------------------------------------------------------- 1 | # Simulation time 2 | 3 | *Defined in header ``*
4 | *Defined in namespace okec::now* 5 | 6 | ||| 7 | |-------------|--------| 8 | |[years](#years)|returns a year in the simulation time
(function)| 9 | |[days](#days)|returns a day of a month in the simulation time
(function)| 10 | |[hours](#hours)|returns an hour of a day in the simulation time
(function)| 11 | |[minutes](#minutes)|returns a minute in the simulation time
(function)| 12 | |[seconds](#seconds)|returns a second in the simulation time
(function)| 13 | |[milli_seconds](#milli_seconds)|returns a millisecond in the simulation time
(function)| 14 | |[micro_seconds](#micro_seconds)|returns a microsecond in the simulation time
(function)| 15 | |[nano_seconds](#nano_seconds)|returns a nanosecond in the simulation time
(function)| 16 | |[pico_seconds](#pico_seconds)|returns a picosecond in the simulation time
(function)| 17 | |[femto_seconds](#femto_seconds)|returns a femtosecond in the simulation time
(function)| 18 | 19 | ## Functions 20 | 21 | ### years 22 | 23 | ```cpp 24 | inline auto years() -> double; 25 | ``` 26 | 27 | ### days 28 | ```cpp 29 | inline auto days() -> double; 30 | ``` 31 | 32 | ### hours 33 | ```cpp 34 | inline auto hours() -> double; 35 | ``` 36 | 37 | ### minutes 38 | ```cpp 39 | inline auto minutes() -> double; 40 | ``` 41 | 42 | ### seconds 43 | ```cpp 44 | inline auto seconds() -> double; 45 | ``` 46 | 47 | ### milli_seconds 48 | ```cpp 49 | inline auto milli_seconds() -> double; 50 | ``` 51 | 52 | ### micro_seconds 53 | ```cpp 54 | inline auto micro_seconds() -> double; 55 | ``` 56 | 57 | ### nano_seconds 58 | ```cpp 59 | inline auto nano_seconds() -> double; 60 | ``` 61 | 62 | ### pico_seconds 63 | ```cpp 64 | inline auto pico_seconds() -> double; 65 | ``` 66 | 67 | ### femto_seconds 68 | ```cpp 69 | inline auto femto_seconds() -> double; 70 | ``` 71 | 72 | ## Example 73 | ```cpp 74 | #include 75 | 76 | 77 | int main() { 78 | okec::print("years: {}\n", okec::now::years()); 79 | okec::print("days: {}\n", okec::now::days()); 80 | okec::print("hours: {}\n", okec::now::hours()); 81 | okec::print("minutes: {}\n", okec::now::minutes()); 82 | okec::print("seconds: {}\n", okec::now::seconds()); 83 | okec::print("milli_seconds: {}\n", okec::now::milli_seconds()); 84 | okec::print("micro_seconds: {}\n", okec::now::micro_seconds()); 85 | okec::print("nano_seconds: {}\n", okec::now::nano_seconds()); 86 | okec::print("pico_seconds: {}\n", okec::now::pico_seconds()); 87 | okec::print("femto_seconds: {}\n", okec::now::femto_seconds()); 88 | } 89 | ``` 90 | 91 | Output: 92 | ```text 93 | years: 0 94 | days: 0 95 | hours: 0 96 | minutes: 0 97 | seconds: 0 98 | milli_seconds: 0 99 | micro_seconds: 0 100 | nano_seconds: 0 101 | pico_seconds: 0 102 | femto_seconds: 0 103 | ``` -------------------------------------------------------------------------------- /docs/okec/components/common/simulator.md: -------------------------------------------------------------------------------- 1 | # okec::simulator 2 | 3 | *Defined in header ``*
4 | *Defined in namespace okec* 5 | 6 | ```cpp 7 | class simulator {}; 8 | ``` 9 | 10 | ## Member functions 11 | 12 | ||| 13 | |-------------|--------| 14 | |[(constructor)](../simulator/simulator)|constructs a new simulator
(public member function)| 15 | |[(destructor)](../simulator/~simulator) |destructs the simulator
(public member function)| 16 | |[run](../simulator/run)|runs the simulator
(public member function)| 17 | |[stop_time (getter)](../simulator/stop_time)|gets the stop time of the simulator
(public member function)| 18 | |[stop_time (setter)](#stop_time-setter)|sets the stop time of the simulator
(public member function)| 19 | |[submit](../simulator/submit)|sets the coroutine resume function
(public member function)| 20 | |[complete](../simulator/complete)|invokes the resume function when the response is arrived
(public member function)| 21 | |[is_valid](../simulator/is_valid)|checks if the ip address has a resume function
(public member function)| 22 | |[hold_coro](../simulator/hold_coro)|holds a awaitable object in case it destroyed
(public member function)| 23 | 24 | 25 | 26 | ### stop_time setter 27 | ```cpp 28 | auto stop_time() const -> ns3::Time; 29 | ``` 30 | 31 | ## Notes 32 | 33 | ## Example -------------------------------------------------------------------------------- /docs/okec/components/common/simulator/compele.md: -------------------------------------------------------------------------------- 1 | #simulator::complete 2 | 3 | ```cpp 4 | auto complete(const std::string& ip, response&& r) -> void; 5 | ``` 6 | 7 | ## Parameters 8 | ## Return value 9 | ## Notes 10 | ## Example -------------------------------------------------------------------------------- /docs/okec/components/common/simulator/hold_coro.md: -------------------------------------------------------------------------------- 1 | #simulator::hold_coro 2 | 3 | ```cpp 4 | auto hold_coro(awaitable a) -> void; 5 | ``` -------------------------------------------------------------------------------- /docs/okec/components/common/simulator/is_valid.md: -------------------------------------------------------------------------------- 1 | #simulator::is_valid 2 | 3 | ```cpp 4 | auto is_valid(const std::string& ip) -> bool; 5 | ``` -------------------------------------------------------------------------------- /docs/okec/components/common/simulator/run.md: -------------------------------------------------------------------------------- 1 | #simulator::run 2 | 3 | ```cpp 4 | auto run() -> void; 5 | ``` 6 | 7 | ## Parameters 8 | ## Return value 9 | ## Notes 10 | ## Example -------------------------------------------------------------------------------- /docs/okec/components/common/simulator/simulator.md: -------------------------------------------------------------------------------- 1 | #simulator::simulator 2 | 3 | ```cpp 4 | simulator(ns3::Time time = ns3::Seconds(300)); 5 | ``` 6 | 7 | ## Parameters 8 | ## Return value 9 | ## Notes 10 | ## Example -------------------------------------------------------------------------------- /docs/okec/components/common/simulator/stop_time.md: -------------------------------------------------------------------------------- 1 | #simulator::stop_time 2 | 3 | ```cpp 4 | auto stop_time(ns3::Time time) -> void; 5 | ``` 6 | 7 | ## Parameters 8 | ## Return value 9 | ## Notes 10 | ## Example -------------------------------------------------------------------------------- /docs/okec/components/common/simulator/submit.md: -------------------------------------------------------------------------------- 1 | #simulator::submit 2 | 3 | ```cpp 4 | auto submit(const std::string& ip, std::function fn) -> void; 5 | ``` 6 | 7 | ## Parameters 8 | ## Return value 9 | ## Notes 10 | ## Example -------------------------------------------------------------------------------- /docs/okec/components/common/simulator/~simulator.md: -------------------------------------------------------------------------------- 1 | #simulator::~simulator 2 | 3 | ```cpp 4 | ~simulator(); 5 | ``` -------------------------------------------------------------------------------- /docs/okec/components/common/task/task.md: -------------------------------------------------------------------------------- 1 | #task::task 2 | 3 | ||| 4 | |----|----| 5 | |`#!cpp task() = default;`|(1)| 6 | |`#!cpp task(json other);`|(2)| 7 | 8 | Constructs a task object. 9 | 10 | - 1) default constructor. 11 | - 2) Constructs a task object from a valid json file. 12 | 13 | ## Parameters 14 | - **other**: a valid json file to copy from 15 | 16 | ## Example 17 | ```cpp 18 | #include 19 | 20 | int main() { 21 | okec::task t; 22 | } 23 | ``` -------------------------------------------------------------------------------- /docs/okec/customization/decision-engines.md: -------------------------------------------------------------------------------- 1 | # Customizing decision engines -------------------------------------------------------------------------------- /docs/okec/customization/network-models.md: -------------------------------------------------------------------------------- 1 | # Customizing network models -------------------------------------------------------------------------------- /docs/okec/customization/resources.md: -------------------------------------------------------------------------------- 1 | # Customizing resources 2 | 3 | ## Custom okec::resource 4 | A single resource can be customized and retrieved using the `attribute()` and `get_value()` methods, respectively. 5 | 6 | ```cpp 7 | auto res = okec::make_resource(); 8 | res->attribute("cpu", okec::rand_range(1.2, 2.4).to_string()); 9 | 10 | okec::print("resource cpu: {}\n", res->get_value("cpu")); 11 | ``` 12 | 13 | However, this approach is generally not recommended. Typically, you should prefer using the `okec::resource_container` to create and initialize resources. 14 | 15 | ## Custom okec::resource_container 16 | As the name suggests, `okec::resource_container` is the container version of `okec::resource`. Using it to create tasks is more straightforward. 17 | 18 | 19 | ```cpp 20 | // Create 10 resources 21 | okec::resource_container resources(10); 22 | resources.initialize([](auto res) { 23 | res->attribute("cpu", okec::rand_range(2.1, 2.2).to_string()); 24 | }); 25 | 26 | okec::print("{:rs}", resources); 27 | ``` 28 | 29 | The output would be: 30 | 31 | ```text 32 | [ 1] cpu: 2.19 33 | [ 2] cpu: 2.17 34 | [ 3] cpu: 2.14 35 | [ 4] cpu: 2.20 36 | [ 5] cpu: 2.15 37 | [ 6] cpu: 2.18 38 | [ 7] cpu: 2.15 39 | [ 8] cpu: 2.16 40 | [ 9] cpu: 2.17 41 | [10] cpu: 2.18 42 | ``` 43 | 44 | ## Resource attributes 45 | Similar to the task type, all attributes in the resource type are customizable, and you should tailor your resource according to the specific offloading algorithms. 46 | 47 | Resources can encompass various device properties, such as device memory, price, resource utilization rates, disk size, and more. 48 | 49 | Note that the types of all attributes and values are strings. -------------------------------------------------------------------------------- /docs/okec/customization/responses.md: -------------------------------------------------------------------------------- 1 | # Customizing responses 2 | 3 | The response type is very similar to the task type. Here's an example: 4 | 5 | ```cpp 6 | // Create responses 7 | okec::response resp; 8 | resp.emplace_back({ 9 | { "time_consuming", okec::rand_value().to_string() }, 10 | { "finished", "Y" } 11 | }); 12 | 13 | okec::print("{:r}", resp); 14 | ``` 15 | 16 | The output would be: 17 | 18 | ```text 19 | [1] finished: Y time_consuming: 0.27 20 | ``` -------------------------------------------------------------------------------- /docs/okec/customization/tasks.md: -------------------------------------------------------------------------------- 1 | # Customizing tasks 2 | 3 | The okec library can define tasks by setting custom attributes and values. 4 | 5 | ## Task header and task body 6 | A task consists of a header and a body. The header contains various information required for task offloading, such as cpu demand, memory demand, source address, etc. The body, which is generally optional, contains the actual set of instructions. In most cases, only the task header is necessary. 7 | 8 | 9 | ```cpp 10 | okec::task t; 11 | t.emplace_back({ 12 | { "id", okec::task::unique_id() } 13 | }, { 14 | { "instructions", "set of instructions" } 15 | }); 16 | 17 | okec::print("{:t}", t); 18 | ``` 19 | 20 | This will create one task with a header and a body: 21 | 22 | ```text 23 | [1] id: 14CD07884A6DD4685B00CC9950EDA4F instructions: set of instructions 24 | ``` 25 | 26 | You can retrieve values from the header or body using the `get_header()` and `get_body()` methods. 27 | 28 | ```cpp 29 | okec::print("id: {}\n", t[0].get_header("id")); 30 | okec::print("instructions: {}\n", t[0].get_body("instructions")); 31 | ``` 32 | 33 | The output would be: 34 | 35 | ```text 36 | id: 57D01B1F4802E95834B48DE31F27999 37 | instructions: set of instructions 38 | ``` 39 | 40 | As you can see, a task is essentially a container holding multiple task elements. To manipulate any of these elements, you can directly use the syntax `[index]` or the method `at(index)`. 41 | 42 | ## Task attributes 43 | All attributes in the task header and task body are customizable. You should tailor your task according to the specific offloading algorithms. 44 | 45 | ```cpp 46 | okec::task t; 47 | t.emplace_back({ 48 | { "id", okec::task::unique_id() }, 49 | { "cpu", okec::rand_range(1.2, 2.4).to_string() }, 50 | { "memory", okec::rand_range(1, 4).to_string() }, 51 | { "deadline", okec::rand_range(2, 5).to_string() }, 52 | { "...", "..." } 53 | }); 54 | ``` 55 | 56 | Note that the types of all attributes and values are strings. 57 | -------------------------------------------------------------------------------- /docs/okec/getting-started/formatting.md: -------------------------------------------------------------------------------- 1 | # Formatting Output 2 | 3 | ## Formatting tasks 4 | The `task` type is formattable in the okec library. Consequently, it can be directly formatted in both the log module and the output module using the syntax `{:t}`, as demonstrated in the following example: 5 | 6 | ```cpp 7 | okec::print("{:t}", t); 8 | olog::info("{:t}", t); 9 | ``` -------------------------------------------------------------------------------- /docs/okec/getting-started/heterogeneous-devices.md: -------------------------------------------------------------------------------- 1 | # Heterogeneous Devices 2 | 3 | ## Create heterogeneous devices with custom resources 4 | In this trivial example, we create a base station connecting several edge servers. All heterogeneous devices initialize network communication using the `multiple_and_single_LAN_WLAN_network_model`. Additionally, we randomly generate some resources and install them on these edge servers. 5 | 6 | ```cpp 7 | #include 8 | 9 | 10 | int main() 11 | { 12 | okec::simulator sim; 13 | 14 | // Create 1 base station 15 | okec::base_station_container base_stations(sim, 1); 16 | // Create 5 edge servers 17 | okec::edge_device_container edge_servers(sim, 5); 18 | // Create 2 user devices 19 | okec::client_device_container user_devices(sim, 2); 20 | 21 | // Connect the base stations and edge servers 22 | base_stations.connect_device(edge_servers); 23 | 24 | // Set the network model for every device 25 | okec::multiple_and_single_LAN_WLAN_network_model model; 26 | okec::network_initializer(model, user_devices, base_stations.get(0)); 27 | 28 | // Initialize the resources for each edge server. 29 | okec::resource_container resources(edge_servers.size()); 30 | resources.initialize([](auto res) { 31 | res->attribute("cpu", okec::rand_range(2.1, 2.2).to_string()); 32 | }); 33 | 34 | // Print resources 35 | okec::print("{:rs}", resources); 36 | 37 | // Install each resource on each edge server. 38 | edge_servers.install_resources(resources); 39 | 40 | // Run the simulator 41 | sim.run(); 42 | } 43 | ``` -------------------------------------------------------------------------------- /docs/okec/getting-started/log.md: -------------------------------------------------------------------------------- 1 | # Log 2 | 3 | This logging module is inspired by [Stargirl](https://x.com/theavalkyrie/status/1768787170137940141). 4 | 5 | ```cpp 6 | #include 7 | 8 | namespace olog = okec::log; 9 | 10 | void generate_task(okec::task& t, int number, std::string const& group) 11 | { 12 | for (auto i = number; i-- > 0;) 13 | { 14 | t.emplace_back({ 15 | { "task_id", okec::task::get_unique_id() }, 16 | { "group", group }, 17 | { "cpu", okec::rand_range(0.2, 1.2).to_string() }, 18 | { "deadline", okec::rand_range(1, 5).to_string() }, 19 | }); 20 | } 21 | } 22 | 23 | int main() 24 | { 25 | olog::set_level(olog::level::all); 26 | 27 | olog::debug("this is a debug message"); 28 | olog::info("this is a info message"); 29 | olog::warning("watch out, this is a warning message"); 30 | olog::success("oh nice, this one is success"); 31 | olog::error("oops, this one is an error"); 32 | 33 | 34 | olog::info("{0:-^{1}}", "", okec::get_winsize().col - olog::indent_size()); 35 | 36 | // Print tasks 37 | okec::task t; 38 | generate_task(t, 5, "dummy"); 39 | okec::print("task:\n{:t}", t); 40 | 41 | olog::info("{0:-^{1}}", "", okec::get_winsize().col - olog::indent_size()); 42 | 43 | // Print resources 44 | okec::resource_container resources(5); 45 | resources.initialize([](auto res) { 46 | res->attribute("cpu", okec::rand_range(2.1, 2.2).to_string()); 47 | res->attribute("memory", okec::rand_range(1, 4).to_string()); 48 | }); 49 | okec::print("resource:\n{:rs}", resources); 50 | 51 | olog::info("{0:-^{1}}", "", okec::get_winsize().col - olog::indent_size()); 52 | } 53 | ``` 54 | 55 | Output: 56 | ![Log](https://github.com/okecsim/okec/raw/main/images/log.png) -------------------------------------------------------------------------------- /docs/okec/getting-started/visualizer.md: -------------------------------------------------------------------------------- 1 | # Visualizer 2 | 3 | ## Response Visualizer 4 | 5 | ```cpp 6 | #include 7 | 8 | namespace olog = okec::log; 9 | 10 | void generate_task(okec::task& t, int number, std::string const& group) 11 | { 12 | for (auto i = number; i-- > 0;) 13 | { 14 | t.emplace_back({ 15 | { "task_id", okec::task::get_unique_id() }, 16 | { "group", group }, 17 | { "cpu", okec::rand_range(0.2, 1.2).to_string() }, 18 | { "deadline", okec::rand_range(1, 5).to_string() }, 19 | }); 20 | } 21 | } 22 | 23 | okec::awaitable offloading(auto user, okec::task t) { 24 | std::vector x_points(t.size()); 25 | std::ranges::iota(x_points, 1); 26 | 27 | co_await user->async_send(std::move(t)); 28 | auto resp = co_await user->async_read(); 29 | olog::success("received response."); 30 | 31 | okec::print("{:r}", resp); 32 | double finished = 0; 33 | std::vector time_points; 34 | for (const auto& item : resp.data()) { 35 | if (item["finished"] == "Y") { 36 | finished++; 37 | time_points.push_back(TO_DOUBLE(item["time_consuming"])); 38 | } 39 | } 40 | 41 | auto total_time = std::accumulate(time_points.begin(), time_points.end(), .0); 42 | okec::print("Task completion rate: {:2.0f}%\n", finished / resp.size() * 100); 43 | okec::print("Total processing time: {:.6f}\n", total_time); 44 | okec::print("Average processing time: {:.6f}\n", total_time / time_points.size()); 45 | 46 | okec::draw(x_points, time_points, "Tasks", "Processing Time(Seconds)"); 47 | } 48 | 49 | int main() 50 | { 51 | olog::set_level(olog::level::all); 52 | okec::simulator sim; 53 | 54 | // Create 1 base station 55 | okec::base_station_container base_stations(sim, 1); 56 | // Create 5 edge servers 57 | okec::edge_device_container edge_servers(sim, 5); 58 | // Create 2 user devices 59 | okec::client_device_container user_devices(sim, 2); 60 | 61 | // Connect the base stations and edge servers 62 | base_stations.connect_device(edge_servers); 63 | 64 | // Set the network model for every device 65 | okec::multiple_and_single_LAN_WLAN_network_model model; 66 | okec::network_initializer(model, user_devices, base_stations.get(0)); 67 | 68 | // Initialize the resources for each edge server. 69 | okec::resource_container resources(edge_servers.size()); 70 | resources.initialize([](auto res) { 71 | res->attribute("cpu", okec::rand_range(2.1, 2.2).to_string()); 72 | }); 73 | 74 | // Install each resource on each edge server. 75 | edge_servers.install_resources(resources); 76 | 77 | // Specify the default offloading strategy 78 | auto decision_engine = std::make_shared(&user_devices, &base_stations); 79 | decision_engine->initialize(); 80 | 81 | 82 | // Offload tasks 83 | okec::task t; 84 | generate_task(t, 5, "1st"); 85 | auto user1 = user_devices.get_device(0); 86 | co_spawn(sim, offloading(user1, t)); 87 | 88 | 89 | // Run the simulator 90 | sim.run(); 91 | } 92 | ``` 93 | 94 | Output: 95 | ![Response Visualizer](https://github.com/okecsim/okec/raw/main/images/response-visualizer.png) 96 | ![Response Draw](https://github.com/okecsim/okec/raw/main/images/response-visualization-demo.png) -------------------------------------------------------------------------------- /docs/page2.md: -------------------------------------------------------------------------------- 1 | # Summary 2 | 3 | Members | Descriptions 4 | --------------------------------|--------------------------------------------- 5 | `namespace `[`transport`](#namespacetransport) | 6 | 7 | # namespace `transport` 8 | 9 | ## Summary 10 | 11 | Members | Descriptions 12 | --------------------------------|--------------------------------------------- 13 | `class `[`transport::Bicycle`](#classtransport_1_1Bicycle) | Standard bicycle class. 14 | `class `[`transport::MountainBike`](#classtransport_1_1MountainBike) | Mountain bike implementation of a `[Bicycle](#classtransport_1_1Bicycle)`. 15 | `class `[`transport::RacingBike`](#classtransport_1_1RacingBike) | Racing bike class. 16 | 17 | ## class `transport::Bicycle` 18 | 19 | Standard bicycle class. 20 | 21 | [Bicycle](#classtransport_1_1Bicycle) implements a standard bicycle. Bicycles are a useful way of transporting oneself, without too much effort (unless you go uphill or against the wind). If there are a lot of people on the road, you can use `RingBell` to ring your bell (**note**, not all bicycles have bells!). 22 | 23 | ### Summary 24 | 25 | Members | Descriptions 26 | --------------------------------|--------------------------------------------- 27 | `public virtual void `[`PedalHarder`](#classtransport_1_1Bicycle_1a7df6cce8f18012fb07bef5be9dadd8ef)`()` | PedalHarder makes you go faster (usually). 28 | `public virtual void `[`RingBell`](#classtransport_1_1Bicycle_1a7d2be572f09c78b4d4ae38ef22f3e98b)`()` | Ring bell on the bike. 29 | `public virtual `[`~Bicycle`](#classtransport_1_1Bicycle_1a5f62d09b772a7705634bfb3551803c25)`()` | Default destructor. 30 | 31 | ### Members 32 | 33 | #### `public virtual void `[`PedalHarder`](#classtransport_1_1Bicycle_1a7df6cce8f18012fb07bef5be9dadd8ef)`()` 34 | 35 | PedalHarder makes you go faster (usually). 36 | 37 | #### `public virtual void `[`RingBell`](#classtransport_1_1Bicycle_1a7d2be572f09c78b4d4ae38ef22f3e98b)`()` 38 | 39 | Ring bell on the bike. 40 | 41 | RingBell rings the bell on the bike. Note that not all bikes have bells. 42 | 43 | #### `public virtual `[`~Bicycle`](#classtransport_1_1Bicycle_1a5f62d09b772a7705634bfb3551803c25)`()` 44 | 45 | Default destructor. 46 | 47 | ## class `transport::MountainBike` 48 | 49 | ``` 50 | class transport::MountainBike 51 | : public transport::Bicycle 52 | ``` 53 | 54 | Mountain bike implementation of a `[Bicycle](#classtransport_1_1Bicycle)`. 55 | 56 | [MountainBike](#classtransport_1_1MountainBike) is an implementation of a [Bicycle](#classtransport_1_1Bicycle) providing a bike for cycling on rough terrain. Mountain bikes are pretty cool because they have stuff like **Suspension** (and you can even adjust it using SetSuspension). If you're looking for a bike for use on the road, you might be better off using a [RacingBike](#classtransport_1_1RacingBike) though. 57 | 58 | ### Summary 59 | 60 | Members | Descriptions 61 | --------------------------------|--------------------------------------------- 62 | `public bool `[`SetSuspension`](#classtransport_1_1MountainBike_1a04caecd7e5ff7572b6ac1dc283510301)`(double stiffness)` | Set suspension stiffness. @stiffness the suspension stiffness. 63 | `public template<>`
`inline bool `[`ChangeBreak`](#classtransport_1_1MountainBike_1afd02513876a196e98acaacdc555aeb52)`(BreakType breakType)` | Change the break type. @BreakType the break type. @breakType the type of the break. 64 | 65 | ### Members 66 | 67 | #### `public bool `[`SetSuspension`](#classtransport_1_1MountainBike_1a04caecd7e5ff7572b6ac1dc283510301)`(double stiffness)` 68 | 69 | Set suspension stiffness. @stiffness the suspension stiffness. 70 | 71 | SetSuspension changes the stiffness of the suspension on the bike. The method will return false if the stiffness could not be adjusted. 72 | 73 | #### Returns 74 | true if the suspension was adjusted successfully, false otherwise. 75 | 76 | #### `public template<>`
`inline bool `[`ChangeBreak`](#classtransport_1_1MountainBike_1afd02513876a196e98acaacdc555aeb52)`(BreakType breakType)` 77 | 78 | Change the break type. @BreakType the break type. @breakType the type of the break. 79 | 80 | ChangesBreak changes the type of break fitted to the bike. The method will return false if the break type could not be fitted. 81 | 82 | #### Returns 83 | true if the break was adjusted successfully. false otherise 84 | 85 | ## class `transport::RacingBike` 86 | 87 | ``` 88 | class transport::RacingBike 89 | : public transport::Bicycle 90 | ``` 91 | 92 | Racing bike class. 93 | 94 | [RacingBike](#classtransport_1_1RacingBike) is a special kind of bike which can go much faster on the road, with much less effort (even uphill!). It doesn't make sense to call `RingBell` on a racing bike for they don't have bells. 95 | 96 | ### Summary 97 | 98 | Members | Descriptions 99 | --------------------------------|--------------------------------------------- 100 | `public virtual void `[`PedalHarder`](#classtransport_1_1RacingBike_1ab557c5727daa07a5001782d5dcd46c5b)`()` | PedalHarder makes you go faster (usually). 101 | `public virtual void `[`RingBell`](#classtransport_1_1RacingBike_1ad32dc3b06a453fba3e20329842bb318b)`()` | Ring bell on the bike. 102 | 103 | ### Members 104 | 105 | #### `public virtual void `[`PedalHarder`](#classtransport_1_1RacingBike_1ab557c5727daa07a5001782d5dcd46c5b)`()` 106 | 107 | PedalHarder makes you go faster (usually). 108 | 109 | #### `public virtual void `[`RingBell`](#classtransport_1_1RacingBike_1ad32dc3b06a453fba3e20329842bb318b)`()` 110 | 111 | Ring bell on the bike. 112 | 113 | RingBell rings the bell on the bike. Note that not all bikes have bells. 114 | 115 | Generated by [Moxygen](https://sourcey.com/moxygen) -------------------------------------------------------------------------------- /docs/stylesheets/extra.css: -------------------------------------------------------------------------------- 1 | :root { 2 | --md-primary-fg-color: #343333; 3 | --md-primary-fg-color--light: #ECB7B7; 4 | --md-primary-fg-color--dark: #90030C; 5 | } 6 | 7 | thead th:empty { 8 | display: none; 9 | } 10 | 11 | tbody td:empty { 12 | padding: 0 !important; 13 | } 14 | 15 | .md-typeset table:not([class]) { 16 | border: none !important; 17 | } 18 | 19 | table code { 20 | background: none !important; 21 | } 22 | 23 | table { 24 | font-size: 16px !important; 25 | } -------------------------------------------------------------------------------- /examples/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.12) 2 | project(examples VERSION 1.0) 3 | 4 | find_package(okec 1.0 CONFIG REQUIRED) 5 | 6 | message(STATUS "okec found: ${okec_FOUND}") 7 | 8 | # add_executable(sixth "src/sixth.cc") 9 | # target_link_libraries(sixth PRIVATE okec::okec) 10 | # target_compile_options(sixth PRIVATE -Wall -g) 11 | 12 | file(GLOB SOURCE_FILES src/*.cc) 13 | list(LENGTH SOURCE_FILES SRC_FILES_SIZE) 14 | message(STATUS "Found ${SRC_FILES_SIZE} source files of examples") 15 | foreach(source_file ${SOURCE_FILES}) 16 | get_filename_component(file_name ${source_file} NAME) 17 | string(REPLACE ".cc" "" name ${file_name}) 18 | message(STATUS " ${name}") 19 | add_executable(${name} "src/${name}.cc") 20 | target_link_libraries(${name} PRIVATE okec::okec) 21 | target_compile_options(${name} PRIVATE -Wall -g) 22 | endforeach() 23 | -------------------------------------------------------------------------------- /examples/scene2-rf-resource_tracer.csv: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | ===================Episode-1=========================== 6 | 7 | 8 | 9 | 0.00 [episode=1],2.11,2.18,2.15,2.15,2.15 10 | 0.00 [episode=1],2.11,2.18,2.15,1.18,2.15 11 | 0.00 [episode=1],2.11,1.87,2.15,1.18,2.15 12 | 0.00 [episode=1],2.11,1.87,2.15,1.18,1.15 13 | 0.00 [episode=1],2.11,1.87,1.35,1.18,1.15 14 | 0.00 [episode=1],2.11,1.66,1.35,1.18,1.15 15 | 0.00 [episode=1],2.11,1.66,0.44,1.18,1.15 16 | 0.11 [episode=1],2.11,1.87,0.44,1.18,1.15 17 | 0.14 [episode=1],2.11,2.18,0.44,1.18,1.15 18 | 0.14 [episode=1],2.11,2.18,0.44,0.36,1.15 19 | 0.14 [episode=1],2.11,2.18,0.05,0.36,1.15 20 | 0.37 [episode=1],2.11,2.18,0.85,0.36,1.15 21 | 0.45 [episode=1],2.11,2.18,0.85,1.33,1.15 22 | 0.47 [episode=1],2.11,2.18,0.85,1.33,2.15 23 | 0.47 [episode=1],2.11,2.18,0.85,0.42,2.15 24 | 0.67 [episode=1],2.11,2.18,1.76,0.42,2.15 25 | 0.67 [episode=1],2.11,1.22,1.76,0.42,2.15 26 | 0.84 [episode=1],2.11,1.22,1.76,1.24,2.15 27 | 1.03 [episode=1],2.11,1.22,2.15,1.24,2.15 28 | 1.11 [episode=1],2.11,2.18,2.15,1.24,2.15 29 | 1.15 [episode=1],2.11,2.18,2.15,2.15,2.15 30 | -------------------------------------------------------------------------------- /examples/src/fifth.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | namespace olog = okec::log; 4 | 5 | 6 | int main() { 7 | olog::set_level(olog::level::all); 8 | 9 | okec::simulator sim; 10 | 11 | // Create 1 base station 12 | okec::base_station_container base_stations(sim, 1); 13 | // Create 5 edge servers 14 | okec::edge_device_container edge_servers(sim, 5); 15 | // Create 2 user devices 16 | okec::client_device_container user_devices(sim, 2); 17 | // Create a cloud 18 | okec::cloud_server cloud(sim); 19 | 20 | // std::vector client_groups; 21 | // client_groups.push_back(std::move(user_devices)); 22 | 23 | // Connect the bs and edge servers 24 | base_stations.connect_device(edge_servers); 25 | 26 | // Set the network model for every device 27 | okec::cloud_edge_end_model model; 28 | okec::network_initializer(model, user_devices, base_stations.get(0), cloud); 29 | 30 | // Initialize the resources for each edge server. 31 | okec::resource_container resources(edge_servers.size()); 32 | resources.initialize([](auto res) { 33 | res->attribute("cpu", okec::rand_range(2.1, 2.2).to_string()); 34 | }); 35 | 36 | // Install each resource on each edge server. 37 | edge_servers.install_resources(resources); 38 | 39 | // Install resource on cloud server 40 | auto cloud_res = okec::make_resource(); 41 | cloud_res->attribute("cpu", "50"); 42 | cloud.install_resource(cloud_res); 43 | 44 | // Specify the default offloading strategy 45 | auto decision_engine = std::make_shared(&user_devices, &base_stations, &cloud); 46 | decision_engine->initialize(); 47 | 48 | 49 | sim.run(); 50 | } -------------------------------------------------------------------------------- /examples/src/rf_discrete.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | 4 | void generate_task(okec::task &t, int number, const std::string& group) { 5 | for ([[maybe_unused]] auto _ : std::views::iota(0, number)) { 6 | t.emplace_back({ 7 | { "task_id", okec::task::unique_id() }, 8 | { "group", group }, 9 | { "cpu", okec::format("{:.2f}", torch::rand({1}).uniform_(0.2, 1.2).item()) }, 10 | { "deadline", okec::format("{:.2f}", torch::rand({1}).uniform_(10, 100).item()) }, 11 | }); 12 | } 13 | 14 | // t.save_to_file("task-" + std::to_string(number) + ".json"); 15 | // t.load_from_file("task-" + std::to_string(number) + ".json"); 16 | } 17 | 18 | int main(int argc, char **argv) 19 | { 20 | okec::log::set_level(okec::log::level::all); 21 | 22 | std::size_t edge_num = 5; 23 | int task_num = 10; 24 | int episode = 1; 25 | 26 | ns3::CommandLine cmd; 27 | cmd.AddValue("edge_num", "edge number", edge_num); 28 | cmd.AddValue("task_num", "task number", task_num); 29 | cmd.AddValue("episode", "train episode", episode); 30 | cmd.Parse(argc, argv); 31 | 32 | okec::print("edge_num: {}, task_num: {}, episode: {}\n", edge_num, task_num, episode); 33 | 34 | okec::simulator sim; 35 | 36 | // Create 2 base stations and connect them with some edge servers. 37 | okec::base_station_container base_stations(sim, 1); 38 | okec::edge_device_container edge_devices1(sim, edge_num); 39 | // okec::edge_device_container edge_devices2(8); 40 | base_stations.connect_device(edge_devices1); 41 | 42 | // Create 2 user groups 43 | // okec::client_device_container client_devices1(2); 44 | // okec::client_device_container client_devices2(2); 45 | // std::vector client_devices; 46 | // client_devices.push_back(std::move(client_devices1)); 47 | // client_devices.push_back(std::move(client_devices2)); 48 | okec::client_device_container user_devices(sim, 2); 49 | 50 | // Initialize the network 51 | okec::multiple_and_single_LAN_WLAN_network_model net_model; 52 | okec::network_initializer(net_model, user_devices, base_stations.get(0)); 53 | 54 | // Create resources. 55 | okec::resource_container edge_resources1(edge_devices1.size()); 56 | // okec::resource_container edge_resources2(edge_devices2.size()); 57 | edge_resources1.initialize([](auto res) { 58 | res->attribute("cpu", okec::format("{:.2f}", torch::rand({1}).uniform_(2.1, 2.2).item())); 59 | }); 60 | // edge_resources1.load_from_file("resource-" + std::to_string(edge_resources1.size()) + ".json"); 61 | // edge_resources2.load_from_file("resource-" + std::to_string(edge_resources2.size()) + ".json"); 62 | edge_resources1.print(); 63 | // edge_resources2.print(); 64 | 65 | // Install resources on edge servers. 66 | edge_devices1.install_resources(edge_resources1); // 一键为所有边缘设备安装资源 67 | // edge_devices2.install_resources(edge_resources2); // 一键为所有边缘设备安装资源 68 | 69 | auto decision_engine = std::make_shared(&user_devices, &base_stations); 70 | decision_engine->initialize(); 71 | 72 | okec::task t; 73 | generate_task(t, task_num, "dummy"); 74 | 75 | auto device_1 = user_devices.get_device(0); 76 | // device_1->send(t); 77 | decision_engine->train(t, episode); 78 | // decision_engine->train(t, device_1, base_stations); 79 | // device_1->send(t); 80 | // device_1->when_done([](okec::response res) { 81 | 82 | // okec::print("task is done!\n"); 83 | // }); 84 | 85 | 86 | sim.run(); 87 | } -------------------------------------------------------------------------------- /examples/src/seventh.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | namespace olog = okec::log; 4 | 5 | 6 | void generate_task(okec::task& t, int number, std::string const& group) 7 | { 8 | // for (auto i = number; i-- > 0;) 9 | // { 10 | // t.emplace_back({ 11 | // { "task_id", okec::task::unique_id() }, 12 | // { "group", group }, 13 | // { "size", okec::rand_range(20, 25).to_string() }, 14 | // { "cpu", okec::rand_range(0.5, 1.5).to_string() }, 15 | // { "deadline", okec::rand_range(2.0, 2.5).to_string() }, 16 | // }); 17 | // } 18 | // t.save_to_file("task-" + std::to_string(number) + ".json"); 19 | t.load_from_file("data/task-" + std::to_string(number) + ".json"); 20 | } 21 | 22 | okec::awaitable offloading(auto user, okec::task t) { 23 | // olog::debug("offloading begin"); 24 | 25 | co_await user->async_send(std::move(t)); 26 | auto resp = co_await user->async_read(); 27 | olog::success("received response.\n"); 28 | 29 | // okec::print("{}\n", resp.dump(2)); 30 | okec::print("{:r}", resp); 31 | double finished = 0; 32 | for (const auto& item : resp.data()) { 33 | if (item["finished"] == "Y") { 34 | finished++; 35 | } 36 | } 37 | okec::print("Task completion rate: {:2.0f}%\n\n", finished / resp.size() * 100); 38 | } 39 | 40 | int main(int argc, char **argv) 41 | { 42 | std::size_t edge_num = 3; 43 | std::size_t task_num = 10; 44 | 45 | ns3::CommandLine cmd; 46 | cmd.AddValue("edge_num", "edge number", edge_num); 47 | cmd.AddValue("task_num", "task number", task_num); 48 | cmd.Parse(argc, argv); 49 | 50 | okec::print("edge_num: {}, task_num: {}\n", edge_num, task_num); 51 | 52 | olog::set_level(olog::level::all); 53 | 54 | okec::simulator sim; 55 | 56 | // Create 1 base station 57 | okec::base_station_container base_stations(sim, 1); 58 | // Create 5 edge servers 59 | okec::edge_device_container edge_servers(sim, edge_num); 60 | // Create 2 user devices 61 | okec::client_device_container user_devices(sim, 2); 62 | // Create a cloud 63 | okec::cloud_server cloud(sim); 64 | 65 | // std::vector client_groups; 66 | // client_groups.push_back(std::move(user_devices)); 67 | 68 | // Connect the bs and edge servers 69 | base_stations.connect_device(edge_servers); 70 | 71 | // Set the network model for every device 72 | okec::cloud_edge_end_model model; 73 | okec::network_initializer(model, user_devices, base_stations.get(0), cloud); 74 | 75 | // Set the location 76 | base_stations.get(0)->set_position(0, 0, 0); 77 | cloud.set_position(100, 0, 0); 78 | 79 | // Initialize the resources for each edge server. 80 | okec::resource_container resources(edge_servers.size()); 81 | resources.initialize([](auto res) { 82 | res->attribute("cpu", okec::rand_range(2.4, 2.8).to_string()); 83 | }); 84 | // resources.save_to_file("resource-" + std::to_string(resources.size()) + ".json"); 85 | // resources.load_from_file("data/resource-" + std::to_string(resources.size()) + ".json"); 86 | okec::print("resources:\n{:rs}\n", resources); 87 | 88 | // Install each resource on each edge server. 89 | edge_servers.install_resources(resources); 90 | 91 | resources.trace_resource(); // 先捕捉初始值 92 | resources.set_monitor([&resources](std::string_view address, std::string_view attr, std::string_view old_val, std::string_view new_val) { 93 | resources.trace_resource(); 94 | }); 95 | 96 | // Install resource on cloud server 97 | auto cloud_res = okec::make_resource(); 98 | cloud_res->attribute("cpu", "20"); 99 | cloud.install_resource(cloud_res); 100 | 101 | // Specify the default offloading strategy 102 | auto decision_engine = std::make_shared(&user_devices, &base_stations, &cloud); 103 | decision_engine->initialize(); 104 | 105 | 106 | okec::task t; 107 | generate_task(t, task_num, "dummy"); 108 | okec::print("task:\n{:t}\n", t); 109 | 110 | auto user1 = user_devices.get_device(0); 111 | co_spawn(sim, offloading(user1, t)); 112 | 113 | 114 | sim.enable_visualizer(); 115 | sim.run(); 116 | } -------------------------------------------------------------------------------- /examples/src/sixth.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | namespace olog = okec::log; 4 | 5 | 6 | void generate_task(okec::task& t, int number, std::string const& group) 7 | { 8 | // for (auto i = number; i-- > 0;) 9 | // { 10 | // t.emplace_back({ 11 | // { "task_id", okec::task::unique_id() }, 12 | // { "group", group }, 13 | // { "size", okec::rand_range(20, 25).to_string() }, 14 | // { "cpu", okec::rand_range(0.5, 1.5).to_string() }, 15 | // { "deadline", okec::rand_range(2.0, 2.5).to_string() }, 16 | // }); 17 | // } 18 | // t.save_to_file("task-" + std::to_string(number) + ".json"); 19 | t.load_from_file("data/task-" + std::to_string(number) + ".json"); 20 | } 21 | 22 | okec::awaitable offloading(auto user, okec::task t) { 23 | // olog::debug("offloading begin"); 24 | 25 | co_await user->async_send(std::move(t)); 26 | auto resp = co_await user->async_read(); 27 | olog::success("received response.\n"); 28 | 29 | // okec::print("{}\n", resp.dump(2)); 30 | okec::print("{:r}", resp); 31 | double finished = 0; 32 | for (const auto& item : resp.data()) { 33 | if (item["finished"] == "Y") { 34 | finished++; 35 | } 36 | } 37 | okec::print("Task completion rate: {:2.0f}%\n\n", finished / resp.size() * 100); 38 | } 39 | 40 | int main(int argc, char **argv) 41 | { 42 | std::size_t edge_num = 3; 43 | std::size_t task_num = 10; 44 | 45 | ns3::CommandLine cmd; 46 | cmd.AddValue("edge_num", "edge number", edge_num); 47 | cmd.AddValue("task_num", "task number", task_num); 48 | cmd.Parse(argc, argv); 49 | 50 | okec::print("edge_num: {}, task_num: {}\n", edge_num, task_num); 51 | 52 | olog::set_level(olog::level::all); 53 | 54 | okec::simulator sim; 55 | // sim.enable_visualizer(); 56 | 57 | // Create 1 base station 58 | okec::base_station_container base_stations(sim, 1); 59 | // Create 5 edge servers 60 | okec::edge_device_container edge_servers(sim, edge_num); 61 | // Create 2 user devices 62 | okec::client_device_container user_devices(sim, 2); 63 | // Create a cloud 64 | okec::cloud_server cloud(sim); 65 | 66 | // std::vector client_groups; 67 | // client_groups.push_back(std::move(user_devices)); 68 | 69 | // Connect the bs and edge servers 70 | base_stations.connect_device(edge_servers); 71 | 72 | // Set the network model for every device 73 | okec::cloud_edge_end_model model; 74 | okec::network_initializer(model, user_devices, base_stations.get(0), cloud); 75 | 76 | auto mobility = std::make_shared(); 77 | // mobility->install(user_devices); // STA 78 | mobility->test(user_devices, "data/ns2mobility.tcl"); 79 | mobility->install(base_stations[0]); // AP 80 | // mobility->set_position(user_devices[0], okec::rand_range(5.0, 10.0), okec::rand_range(10.0, 20.0), .0); 81 | mobility->set_position(base_stations[0], 0, 0, 0); 82 | mobility->set_position(cloud, 1000000, 0, 0); 83 | 84 | auto pos = user_devices[0]->get_position(); 85 | okec::print("x: {}, y: {}, z: {}", pos.x, pos.y, pos.z); 86 | 87 | 88 | // Set the location 89 | // base_stations.get(0)->set_position(0, 0, 0); 90 | // cloud.set_position(1000000, 0, 0); 91 | 92 | // Initialize the resources for each edge server. 93 | okec::resource_container resources(edge_servers.size()); 94 | // resources.initialize([](auto res) { 95 | // res->attribute("cpu", okec::rand_range(2.4, 2.8).to_string()); 96 | // }); 97 | // resources.save_to_file("resource-" + std::to_string(resources.size()) + ".json"); 98 | resources.load_from_file("data/resource-" + std::to_string(resources.size()) + ".json"); 99 | okec::print("resources:\n{:rs}\n", resources); 100 | 101 | // Install each resource on each edge server. 102 | edge_servers.install_resources(resources); 103 | 104 | resources.trace_resource(); // 先捕捉初始值 105 | resources.set_monitor([&resources](std::string_view address, std::string_view attr, std::string_view old_val, std::string_view new_val) { 106 | resources.trace_resource(); 107 | }); 108 | 109 | // Install resource on cloud server 110 | auto cloud_res = okec::make_resource(); 111 | cloud_res->attribute("cpu", "20"); 112 | cloud.install_resource(cloud_res); 113 | 114 | // Specify the default offloading strategy 115 | auto decision_engine = std::make_shared(&user_devices, &base_stations, &cloud); 116 | decision_engine->initialize(); 117 | 118 | 119 | okec::task t; 120 | generate_task(t, task_num, "dummy"); 121 | okec::print("task:\n{:t}\n", t); 122 | 123 | auto user1 = user_devices.get_device(0); 124 | co_spawn(sim, offloading(user1, t)); 125 | 126 | sim.run(); 127 | } -------------------------------------------------------------------------------- /examples/src/wf_async.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace okec; 4 | 5 | void generate_task(okec::task &t, int number, const std::string& group) { 6 | for ([[maybe_unused]] auto _ : std::views::iota(0, number)) { 7 | t.emplace_back({ 8 | { "task_id", okec::task::unique_id() }, 9 | { "group", group }, 10 | { "cpu", okec::rand_range(0.2, 1.2).to_string() }, 11 | { "deadline", okec::rand_range(10, 100).to_string() }, 12 | }); 13 | } 14 | } 15 | 16 | void my_monitor(std::string_view address, std::string_view attr, std::string_view old_val, std::string_view new_val) { 17 | static std::ofstream file; 18 | if (!file.is_open()) { 19 | file.open("my_monitor.csv", std::ios::out/* | std::ios::app*/); 20 | if (!file.is_open()) { 21 | return; 22 | } 23 | } 24 | 25 | file << okec::format("At time {:.2f}s,{},{},{}\n", okec::now::seconds(), address, old_val, new_val); 26 | } 27 | 28 | okec::awaitable offloading(auto user, okec::task t) { 29 | log::debug("offloading begin"); 30 | 31 | co_await user->async_send(std::move(t)); 32 | auto resp = co_await user->async_read(); 33 | log::success("received resp."); 34 | 35 | okec::print("{:r}", resp); 36 | 37 | 38 | // double finished = 0; 39 | // int index = 1; 40 | // std::vector time_points; 41 | // okec::print("{0:=^{1}}\n", "Response Info", okec::get_winsize().col); 42 | // for (const auto& item : resp.data()) { 43 | // okec::print("[{:>3}] ", index++); 44 | // okec::print("task_id: {}, device_type: {:>5}, device_address: {:>10}, group: {}, time_consuming: {:>11}s, finished: {}\n", 45 | // item["task_id"], item["device_type"], item["device_address"], item["group"], item["time_consuming"], item["finished"]); 46 | // if (item["finished"] == "Y") { 47 | // finished++; 48 | // time_points.push_back(TO_DOUBLE(item["time_consuming"])); 49 | // } 50 | // } 51 | 52 | // auto total_time = std::accumulate(time_points.begin(), time_points.end(), .0); 53 | // okec::print("Task completion rate: {:2.0f}%\n", finished / resp.size() * 100); 54 | // okec::print("Total processing time: {:.6f}\n", total_time); 55 | // okec::print("Average processing time: {:.6f}\n", total_time / time_points.size()); 56 | // okec::print("{0:=^{1}}", "", okec::get_winsize().col); 57 | } 58 | 59 | int main(int argc, char **argv) 60 | { 61 | log::set_level(log::level::all); 62 | 63 | okec::simulator sim; 64 | 65 | // Create 1 base station 66 | okec::base_station_container bs(sim, 1); 67 | // Create 5 edge servers 68 | okec::edge_device_container edge_servers(sim, 5); 69 | // Create 2 user devices 70 | okec::client_device_container user_devices(sim, 2); 71 | 72 | // Connect the bs and edge servers 73 | bs.connect_device(edge_servers); 74 | 75 | // Set the network model for every device 76 | okec::multiple_and_single_LAN_WLAN_network_model model; 77 | okec::network_initializer(model, user_devices, bs.get(0)); 78 | 79 | // Initialize the resources for each edge server. 80 | okec::resource_container edge_resources(edge_servers.size()); 81 | edge_resources.initialize([](auto res) { 82 | res->attribute("cpu", okec::rand_range(2.1, 2.2).to_string()); 83 | }); 84 | okec::print("{:rs}", edge_resources); 85 | 86 | // Install each resource on each edge server. 87 | edge_servers.install_resources(edge_resources); 88 | 89 | edge_resources.trace_resource(); // 先捕捉初始值 90 | edge_resources.set_monitor([&edge_resources](std::string_view address, std::string_view attr, std::string_view old_val, std::string_view new_val) { 91 | edge_resources.trace_resource(); 92 | }); 93 | 94 | // Set decision engine 95 | auto decision_engine = std::make_shared(&user_devices, &bs); 96 | decision_engine->initialize(); 97 | 98 | okec::task t1; 99 | generate_task(t1, 100, "1st"); 100 | auto user1 = user_devices.get_device(0); 101 | co_spawn(sim, offloading(user1, t1)); 102 | 103 | log::debug("main-1--"); 104 | 105 | okec::task t2; 106 | generate_task(t2, 1, "2st"); 107 | auto user2 = user_devices.get_device(1); 108 | co_spawn(sim, offloading(user2, t2)); 109 | 110 | log::debug("main-2--"); 111 | 112 | // sim.enable_visualizer(); 113 | sim.run(); 114 | } -------------------------------------------------------------------------------- /examples/src/wf_discrete.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | 4 | void generate_task(okec::task &t, int number, const std::string& group) { 5 | for ([[maybe_unused]] auto _ : std::views::iota(0, number)) { 6 | t.emplace_back({ 7 | { "task_id", okec::task::unique_id() }, 8 | { "group", group }, 9 | { "cpu", okec::format("{:.2f}", torch::rand({1}).uniform_(0.2, 1.2).item()) }, 10 | { "deadline", okec::format("{:.2f}", torch::rand({1}).uniform_(10, 100).item()) }, 11 | }); 12 | } 13 | 14 | // t.save_to_file("task-" + std::to_string(number) + ".json"); 15 | // t.load_from_file("task-" + std::to_string(number) + ".json"); 16 | } 17 | 18 | int main(int argc, char **argv) 19 | { 20 | okec::log::set_level(okec::log::level::all); 21 | 22 | std::size_t edge_num = 5; 23 | std::size_t task_num = 10; 24 | 25 | ns3::CommandLine cmd; 26 | cmd.AddValue("edge_num", "edge number", edge_num); 27 | cmd.AddValue("task_num", "task number", task_num); 28 | cmd.Parse(argc, argv); 29 | 30 | okec::print("edge_num: {}, task_num: {}\n", edge_num, task_num); 31 | 32 | 33 | okec::simulator sim; 34 | 35 | // Create 2 base stations and connect them with some edge serves. 36 | okec::base_station_container base_stations(sim, 1); 37 | okec::edge_device_container edge_devices1(sim, edge_num); 38 | // okec::edge_device_container edge_devices2(8); 39 | base_stations.connect_device(edge_devices1); 40 | 41 | // Create 2 user groups 42 | // okec::client_device_container client_devices1(2); 43 | // okec::client_device_container client_devices2(2); 44 | // std::vector client_devices; 45 | // client_devices.push_back(std::move(client_devices1)); 46 | // client_devices.push_back(std::move(client_devices2)); 47 | okec::client_device_container user_devices(sim, 2); 48 | 49 | // Initialize the network 50 | okec::multiple_and_single_LAN_WLAN_network_model net_model; 51 | okec::network_initializer(net_model, user_devices, base_stations.get(0)); 52 | 53 | // Create resources. 54 | okec::resource_container edge_resources1(edge_devices1.size()); 55 | edge_resources1.initialize([](auto res) { 56 | res->attribute("cpu", okec::format("{:.2f}", torch::rand({1}).uniform_(2.1, 2.2).item())); 57 | }); 58 | // edge_resources1.save_to_file("resource-" + std::to_string(edge_resources1.size()) + ".json"); 59 | // edge_resources1.load_from_file("resource-" + std::to_string(edge_resources1.size()) + ".json"); 60 | // edge_resources2.load_from_file("resource-" + std::to_string(edge_resources2.size()) + ".json"); 61 | edge_resources1.print(); 62 | // edge_resources2.print(); 63 | 64 | // Install resources on edge servers. 65 | edge_devices1.install_resources(edge_resources1); // 一键为所有边缘设备安装资源 66 | // edge_devices2.install_resources(edge_resources2); // 一键为所有边缘设备安装资源 67 | 68 | auto decision_engine = std::make_shared(&user_devices, &base_stations); 69 | decision_engine->initialize(); 70 | 71 | okec::task t; 72 | generate_task(t, task_num, "dummy"); 73 | 74 | auto device_1 = user_devices.get_device(0); 75 | // device_1->send(t); 76 | decision_engine->train(t); 77 | // decision_engine->train(t, device_1, base_stations); 78 | // device_1->send(t); 79 | // device_1->when_done([](okec::response res) { 80 | 81 | // okec::print("task is done!\n"); 82 | // }); 83 | 84 | 85 | sim.run(); 86 | } -------------------------------------------------------------------------------- /examples/src/wf_net.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void generate_task(okec::task &t, int number, const std::string& group) { 4 | for ([[maybe_unused]] auto _ : std::views::iota(0, number)) { 5 | t.emplace_back({ 6 | { "task_id", okec::task::unique_id() }, 7 | { "group", group }, 8 | { "cpu", okec::rand_range(0.2, 1.2).to_string() }, 9 | { "deadline", okec::rand_range(10, 100).to_string() } 10 | }); 11 | } 12 | 13 | // t.save_to_file("task-" + std::to_string(number) + ".json"); 14 | // t.load_from_file("data/task-" + std::to_string(number) + ".json"); 15 | } 16 | 17 | void my_monitor(std::string_view address, std::string_view attr, std::string_view old_val, std::string_view new_val) { 18 | static std::ofstream file; 19 | if (!file.is_open()) { 20 | file.open("my_monitor.csv", std::ios::out/* | std::ios::app*/); 21 | if (!file.is_open()) { 22 | return; 23 | } 24 | } 25 | 26 | file << okec::format("At time {:.2f}s,{},{},{}\n", ns3::Simulator::Now().GetSeconds(), address, old_val, new_val); 27 | } 28 | 29 | int main(int argc, char **argv) 30 | { 31 | okec::log::set_level(okec::log::level::debug | okec::log::level::success); 32 | okec::log::set_level(okec::log::level::debug, false); 33 | okec::log::set_level(okec::log::level::info); 34 | 35 | okec::simulator sim; 36 | sim.enable_visualizer(); 37 | 38 | // Create 1 base station 39 | okec::base_station_container bs(sim, 1); 40 | // Create 5 edge servers 41 | okec::edge_device_container edge_servers(sim, 5); 42 | // Create 2 user devices 43 | okec::client_device_container user_devices(sim, 2); 44 | 45 | // Connect the bs and edge servers 46 | bs.connect_device(edge_servers); 47 | 48 | // Set the network model for every device 49 | okec::multiple_and_single_LAN_WLAN_network_model model; 50 | okec::network_initializer(model, user_devices, bs.get(0)); 51 | 52 | // Initialize the resources for each edge server. 53 | okec::resource_container edge_resources(edge_servers.size()); 54 | edge_resources.initialize([](auto res) { 55 | res->attribute("cpu", okec::format("{:.2f}", torch::rand({1}).uniform_(2.1, 2.2).item())); 56 | }); 57 | // edge_resources.save_to_file("resource-" + std::to_string(edge_resources.size()) + ".json"); 58 | // edge_resources.load_from_file("data/resource-" + std::to_string(edge_resources.size()) + ".json"); 59 | 60 | // edge_resources.print(); 61 | 62 | // Install each resource on each edge server. 63 | edge_servers.install_resources(edge_resources); 64 | 65 | edge_resources.trace_resource(); // 先捕捉初始值 66 | edge_resources.set_monitor([&edge_resources](std::string_view address, std::string_view attr, std::string_view old_val, std::string_view new_val) { 67 | // edge_resources.print(); 68 | edge_resources.trace_resource(); 69 | }); 70 | 71 | // Set decision engine 72 | auto decision_engine = std::make_shared(&user_devices, &bs); 73 | decision_engine->initialize(); 74 | 75 | std::vector groups = { "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten", 76 | "eleven", "twelve", "thirteen", "fourteen", "fifteen", "sixteen", "seventeen", "eighteen", "nineteen", "twenty", 77 | "twenty-one", "twenty-two", "twenty-three", "twenty-four", "twenty-five", "twenty-six", "twenty-seven", "twenty-eight", "twenty-nine", "thirty" }; 78 | 79 | // Initialize a task 80 | std::vector tasks(1); // 10 batch of tasks 81 | std::vector time_total_points; 82 | std::vector time_average_points; 83 | std::vector x_points; 84 | 85 | // Client request someone to handle the task. 86 | auto user = user_devices.get_device(0); 87 | user->async_read([&time_total_points, &time_average_points, &x_points, task_size = tasks.size()](okec::response response) { 88 | okec::print("{0:=^{1}}\n", "Response Info", 180); 89 | double finished = 0; 90 | int index = 1; 91 | std::vector time_points; 92 | for (const auto& item : response.data()) { 93 | okec::print("[{:>3}] ", index++); 94 | okec::print("task_id: {}, device_type: {:>5}, device_address: {:>10}, group: {}, time_consuming: {:>11}s, finished: {}\n", 95 | TO_STR(item["task_id"]), TO_STR(item["device_type"]), TO_STR(item["device_address"]), TO_STR(item["group"]), TO_STR(item["time_consuming"]), TO_STR(item["finished"])); 96 | if (item["finished"] == "Y") { 97 | finished++; 98 | time_points.push_back(TO_DOUBLE(item["time_consuming"])); 99 | } 100 | } 101 | 102 | auto total_time = std::accumulate(time_points.begin(), time_points.end(), .0); 103 | okec::print("Task completion rate: {:2.0f}%\n", finished / response.size() * 100); 104 | okec::print("Total processing time: {:.6f}\n", total_time); 105 | okec::print("Average processing time: {:.6f}\n", total_time / time_points.size()); 106 | 107 | okec::print("{0:=^{1}}\n", "", 180); 108 | 109 | // okec::draw(time_points, "Time Comsumption(Seconds)"); 110 | time_total_points.push_back(total_time); 111 | time_average_points.push_back(total_time / time_points.size()); 112 | 113 | if (time_total_points.size() == task_size) { 114 | // std::format doesn't format ranges in C++20. 115 | // Comment below 3 lines for compiling. 116 | // okec::print("time_total_points: {}\n", time_total_points); 117 | // okec::print("time_average_points: {}\n", time_average_points); 118 | // okec::print("x_points: {}\n", x_points); 119 | 120 | 121 | // okec::draw(x_points, time_total_points, "Number of tasks", "Total Processing Time(Seconds)"); 122 | // okec::draw(x_points, time_average_points, "Number of tasks", "Average Processing Time(Seconds)"); 123 | } 124 | }); 125 | 126 | // int step = 50; 127 | // for (auto i = 0uz; i < tasks.size(); ++i, step += 50) { 128 | // generate_task(tasks[i], step, groups[i]); 129 | // x_points.push_back(tasks[i].size()); 130 | // user->send(tasks[i]); 131 | // } 132 | // int step = 50; 133 | // int index = step / 50 - 1; 134 | // generate_task(tasks[0], step, groups[index]); 135 | // x_points.push_back(tasks[0].size()); 136 | // user->send(tasks[0]); 137 | 138 | // !!! 目前记得修改 worse_fit 267 行的任务数,以保证执行效果不受网络影响 139 | generate_task(tasks[0], 50, "dummy"); 140 | x_points.push_back(tasks[0].size()); 141 | user->send(tasks[0]); 142 | 143 | okec::task t2; // 10 batch of tasks 144 | generate_task(t2, 3, "2nd"); 145 | user->send(t2); 146 | 147 | 148 | sim.run(); 149 | } -------------------------------------------------------------------------------- /images/discretely-offload-the-task-using-the-dqn-decision-engine.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dxnu/okec/72d45b5395ad7932a06c2d2bd9acc1957f854aa9/images/discretely-offload-the-task-using-the-dqn-decision-engine.png -------------------------------------------------------------------------------- /images/log.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dxnu/okec/72d45b5395ad7932a06c2d2bd9acc1957f854aa9/images/log.png -------------------------------------------------------------------------------- /images/network-model-1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dxnu/okec/72d45b5395ad7932a06c2d2bd9acc1957f854aa9/images/network-model-1.jpg -------------------------------------------------------------------------------- /images/network-model-2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dxnu/okec/72d45b5395ad7932a06c2d2bd9acc1957f854aa9/images/network-model-2.jpg -------------------------------------------------------------------------------- /images/network-model-3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dxnu/okec/72d45b5395ad7932a06c2d2bd9acc1957f854aa9/images/network-model-3.jpg -------------------------------------------------------------------------------- /images/offloading-your-first-set-of-tasks-using-the-worst-fit-decision-engine.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dxnu/okec/72d45b5395ad7932a06c2d2bd9acc1957f854aa9/images/offloading-your-first-set-of-tasks-using-the-worst-fit-decision-engine.png -------------------------------------------------------------------------------- /images/okec.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dxnu/okec/72d45b5395ad7932a06c2d2bd9acc1957f854aa9/images/okec.jpeg -------------------------------------------------------------------------------- /images/response-visualization-demo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dxnu/okec/72d45b5395ad7932a06c2d2bd9acc1957f854aa9/images/response-visualization-demo.png -------------------------------------------------------------------------------- /images/response-visualizer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dxnu/okec/72d45b5395ad7932a06c2d2bd9acc1957f854aa9/images/response-visualizer.png -------------------------------------------------------------------------------- /include/okec/algorithms/classic/cloud_edge_end_default_decision_engine.h: -------------------------------------------------------------------------------- 1 | #ifndef OKEC_CLOUD_EDGE_END_DEFAULT_DECISION_ENGINE_H_ 2 | #define OKEC_CLOUD_EDGE_END_DEFAULT_DECISION_ENGINE_H_ 3 | 4 | #include 5 | 6 | 7 | namespace okec 8 | { 9 | 10 | class client_device; 11 | class client_device_container; 12 | class edge_device; 13 | class cloud_server; 14 | 15 | 16 | class cloud_edge_end_default_decision_engine : public decision_engine 17 | { 18 | using this_type = cloud_edge_end_default_decision_engine; 19 | 20 | public: 21 | cloud_edge_end_default_decision_engine() = default; 22 | cloud_edge_end_default_decision_engine(client_device_container* clients, base_station_container* base_stations, cloud_server* cloud); 23 | 24 | auto make_decision(const task_element& header) -> result_t override; 25 | 26 | auto local_test(const task_element& header, client_device* client) -> bool override; 27 | 28 | auto send(task_element t, std::shared_ptr client) -> bool override; 29 | 30 | auto initialize() -> void override; 31 | 32 | auto train(const task& train_task, int episode = 1) -> void; 33 | 34 | auto handle_next() -> void override; 35 | 36 | private: 37 | auto on_bs_decision_message(base_station* bs, ns3::Ptr packet, const ns3::Address& remote_address) -> void; 38 | 39 | auto on_bs_response_message(base_station* bs, ns3::Ptr packet, const ns3::Address& remote_address) -> void; 40 | 41 | auto on_es_handling_message(edge_device* es, ns3::Ptr packet, const ns3::Address& remote_address) -> void; 42 | 43 | auto on_cloud_handling_message(cloud_server* cs, ns3::Ptr packet, const ns3::Address& remote_address) -> void; 44 | 45 | auto on_clients_reponse_message(client_device* client, ns3::Ptr packet, const ns3::Address& remote_address) -> void; 46 | 47 | private: 48 | client_device_container* clients_{}; 49 | std::vector* clients_container_{}; 50 | base_station_container* base_stations_{}; 51 | }; 52 | 53 | 54 | } // namespace okec 55 | 56 | #endif // OKEC_CLOUD_EDGE_END_DEFAULT_DECISION_ENGINE_H_ -------------------------------------------------------------------------------- /include/okec/algorithms/classic/worst_fit_decision_engine.h: -------------------------------------------------------------------------------- 1 | /////////////////////////////////////////////////////////////////////////////// 2 | // __ __ _ ____ ___ 3 | // / \( / )( __)/ __) OKEC(a.k.a. EdgeSim++) 4 | // ( O )) ( ) _)( (__ version 1.0.1 5 | // \__/(__\_)(____)\___) https://github.com/dxnu/okec 6 | // 7 | // Copyright (C) 2023-2024 Gaoxing Li 8 | // Licenced under Apache-2.0 license. See LICENSE.txt for details. 9 | /////////////////////////////////////////////////////////////////////////////// 10 | 11 | #ifndef OKEC_WORST_FIT_DECISION_ENGINE_H_ 12 | #define OKEC_WORST_FIT_DECISION_ENGINE_H_ 13 | 14 | #include 15 | 16 | 17 | namespace okec 18 | { 19 | 20 | class client_device; 21 | class client_device_container; 22 | class edge_device; 23 | 24 | class DiscreteEnv : public std::enable_shared_from_this { 25 | using this_type = DiscreteEnv; 26 | using done_callback_t = std::function; 27 | 28 | public: 29 | DiscreteEnv(const device_cache& cache, const task& t); 30 | 31 | auto train() -> void; 32 | auto train_next() -> void; 33 | 34 | auto when_done(done_callback_t callback) -> void; 35 | 36 | auto trace_resource() -> void; 37 | 38 | private: 39 | task t_; 40 | device_cache cache_; 41 | std::vector state_; // 初始状态 42 | done_callback_t done_fn_; 43 | }; 44 | 45 | 46 | class worst_fit_decision_engine : public decision_engine 47 | { 48 | using this_type = worst_fit_decision_engine; 49 | 50 | public: 51 | worst_fit_decision_engine() = default; 52 | worst_fit_decision_engine(client_device_container* clients, base_station_container* base_stations); 53 | worst_fit_decision_engine(std::vector* clients_container, base_station_container* base_stations); 54 | 55 | auto make_decision(const task_element& header) -> result_t override; 56 | 57 | auto local_test(const task_element& header, client_device* client) -> bool override; 58 | 59 | auto send(task_element t, std::shared_ptr client) -> bool override; 60 | 61 | auto initialize() -> void override; 62 | 63 | auto handle_next() -> void override; 64 | 65 | auto train(const task& t) -> void; 66 | 67 | private: 68 | auto on_bs_decision_message(base_station* bs, ns3::Ptr packet, const ns3::Address& remote_address) -> void; 69 | 70 | auto on_bs_response_message(base_station* bs, ns3::Ptr packet, const ns3::Address& remote_address) -> void; 71 | 72 | auto on_es_handling_message(edge_device* es, ns3::Ptr packet, const ns3::Address& remote_address) -> void; 73 | 74 | auto on_clients_reponse_message(client_device* client, ns3::Ptr packet, const ns3::Address& remote_address) -> void; 75 | 76 | private: 77 | client_device_container* clients_{}; 78 | std::vector* clients_container_{}; 79 | base_station_container* base_stations_{}; 80 | }; 81 | 82 | 83 | } // namespace okec 84 | 85 | #endif // OKEC_WORST_FIT_DECISION_ENGINE_H_ -------------------------------------------------------------------------------- /include/okec/algorithms/decision_engine.h: -------------------------------------------------------------------------------- 1 | /////////////////////////////////////////////////////////////////////////////// 2 | // __ __ _ ____ ___ 3 | // / \( / )( __)/ __) OKEC(a.k.a. EdgeSim++) 4 | // ( O )) ( ) _)( (__ version 1.0.1 5 | // \__/(__\_)(____)\___) https://github.com/dxnu/okec 6 | // 7 | // Copyright (C) 2023-2024 Gaoxing Li 8 | // Licenced under Apache-2.0 license. See LICENSE.txt for details. 9 | /////////////////////////////////////////////////////////////////////////////// 10 | 11 | #ifndef OKEC_DECISION_ENGINE_H_ 12 | #define OKEC_DECISION_ENGINE_H_ 13 | 14 | #include 15 | #include 16 | #include 17 | 18 | 19 | namespace okec 20 | { 21 | 22 | class base_station; 23 | class base_station_container; 24 | class client_device; 25 | class edge_device; 26 | class cloud_server; 27 | 28 | 29 | class device_cache 30 | { 31 | public: 32 | using attribute_type = std::pair; 33 | using attributes_type = std::initializer_list; 34 | using value_type = json; 35 | using iterator = json::iterator; 36 | using const_iterator = json::const_iterator; 37 | using unary_predicate_type = std::function; 38 | using binary_predicate_type = std::function; 39 | 40 | public: 41 | 42 | auto begin() -> iterator; 43 | auto end() -> iterator; 44 | 45 | auto cbegin() const -> json::const_iterator; 46 | auto cend() const -> json::const_iterator; 47 | 48 | auto dump(int indent = -1) const -> std::string; 49 | 50 | auto data() const -> value_type; 51 | 52 | auto view() -> value_type&; 53 | 54 | auto size() const -> std::size_t; 55 | 56 | auto empty() const -> bool; 57 | 58 | auto emplace_back(attributes_type values) -> void; 59 | 60 | auto find_if(unary_predicate_type pred) -> iterator; 61 | 62 | auto sort(binary_predicate_type comp) -> void; 63 | 64 | private: 65 | auto emplace_back(value_type item) -> void; 66 | 67 | private: 68 | value_type cache; 69 | }; 70 | 71 | 72 | class decision_engine 73 | : public std::enable_shared_from_this 74 | { 75 | protected: 76 | std::shared_ptr m_decision_device; 77 | 78 | using result_t = json; 79 | 80 | template 81 | auto shared_from_base() -> std::shared_ptr { 82 | return std::static_pointer_cast(this->shared_from_this()); 83 | } 84 | 85 | auto resource_changed(edge_device* es, ns3::Ipv4Address remote_ip, uint16_t remote_port) -> void; 86 | auto conflict(edge_device* es, const task_element& item, ns3::Ipv4Address remote_ip, uint16_t remote_port) -> void; 87 | 88 | public: 89 | virtual ~decision_engine() {} 90 | 91 | auto calculate_distance(const ns3::Vector& pos) -> double; 92 | auto calculate_distance(double x, double y, double z) -> double; 93 | 94 | auto initialize_device(base_station_container* bs_container, cloud_server* cs) -> void; 95 | auto initialize_device(base_station_container* bs_container) -> void; 96 | 97 | virtual auto make_decision(const task_element& header) -> result_t = 0; 98 | 99 | virtual auto local_test(const task_element& header, client_device* client) -> bool = 0; 100 | 101 | virtual auto send(task_element t, std::shared_ptr client) -> bool = 0; 102 | 103 | virtual auto initialize() -> void = 0; 104 | 105 | virtual auto handle_next() -> void = 0; 106 | 107 | auto get_decision_device() const -> std::shared_ptr; 108 | 109 | auto cache() -> device_cache&; 110 | 111 | private: 112 | device_cache m_device_cache; 113 | std::pair m_cs_address; 114 | std::tuple m_cs_info; 115 | }; 116 | 117 | 118 | 119 | #define TO_STR(e) e.template get() 120 | #define TO_INT(e) std::stoi(TO_STR(e)) 121 | #define TO_DOUBLE(e) std::stod(TO_STR(e)) 122 | 123 | 124 | } // namespace okec 125 | 126 | #endif // OKEC_DECISION_ENGINE_H_ -------------------------------------------------------------------------------- /include/okec/algorithms/machine_learning/DQN_decision_engine.h: -------------------------------------------------------------------------------- 1 | /////////////////////////////////////////////////////////////////////////////// 2 | // __ __ _ ____ ___ 3 | // / \( / )( __)/ __) OKEC(a.k.a. EdgeSim++) 4 | // ( O )) ( ) _)( (__ version 1.0.1 5 | // \__/(__\_)(____)\___) https://github.com/dxnu/okec 6 | // 7 | // Copyright (C) 2023-2024 Gaoxing Li 8 | // Licenced under Apache-2.0 license. See LICENSE.txt for details. 9 | /////////////////////////////////////////////////////////////////////////////// 10 | 11 | #ifndef OKEC_DQN_DECISION_ENGINE_H_ 12 | #define OKEC_DQN_DECISION_ENGINE_H_ 13 | 14 | #include 15 | #include 16 | #include 17 | 18 | 19 | namespace okec 20 | { 21 | 22 | class client_device; 23 | class client_device_container; 24 | class edge_device; 25 | 26 | 27 | class Env : public std::enable_shared_from_this { 28 | using this_type = Env; 29 | using done_callback_t = std::function; 30 | 31 | public: 32 | Env(const device_cache& cache, const task& t, std::shared_ptr RL); 33 | 34 | auto next_observation() -> torch::Tensor; 35 | 36 | auto reset() -> torch::Tensor; // 暂时用不到 37 | 38 | auto train() -> void; 39 | auto train_next(torch::Tensor observation) -> void; 40 | 41 | auto when_done(done_callback_t callback) -> void; 42 | 43 | auto print_cache() -> void; 44 | 45 | auto learn(std::size_t step) -> void; 46 | 47 | auto trace_resource(int flag = 0) -> void; 48 | 49 | int episode; 50 | 51 | private: 52 | task t_; 53 | device_cache cache_; 54 | std::shared_ptr RL_; 55 | std::size_t step_; 56 | std::vector state_; // 初始状态 57 | torch::Tensor observation_; 58 | done_callback_t done_fn_; 59 | }; 60 | 61 | 62 | class DQN_decision_engine : public decision_engine 63 | { 64 | using this_type = DQN_decision_engine; 65 | 66 | public: 67 | DQN_decision_engine() = default; 68 | DQN_decision_engine(client_device_container* clients, base_station_container* base_stations); 69 | DQN_decision_engine(std::vector* clients_container, base_station_container* base_stations); 70 | 71 | auto make_decision(const task_element& header) -> result_t override; 72 | 73 | auto local_test(const task_element& header, client_device* client) -> bool override; 74 | 75 | auto send(task_element t, std::shared_ptr client) -> bool override; 76 | 77 | auto train(const task& train_task, int episode = 1) -> void; 78 | 79 | auto initialize() -> void override; 80 | 81 | auto handle_next() -> void override; 82 | 83 | private: 84 | auto on_bs_decision_message(base_station* bs, ns3::Ptr packet, const ns3::Address& remote_address) -> void; 85 | 86 | auto on_bs_response_message(base_station* bs, ns3::Ptr packet, const ns3::Address& remote_address) -> void; 87 | 88 | auto on_cs_handling_message(cloud_server* cs, ns3::Ptr packet, const ns3::Address& remote_address) -> void; 89 | 90 | auto on_es_handling_message(edge_device* es, ns3::Ptr packet, const ns3::Address& remote_address) -> void; 91 | 92 | auto on_clients_reponse_message(client_device* client, ns3::Ptr packet, const ns3::Address& remote_address) -> void; 93 | 94 | // episode: current episode_all: total episode 95 | auto train_start(const task& train_task, int episode, int episode_all) -> void; 96 | 97 | private: 98 | client_device_container* clients_{}; 99 | std::vector* clients_container_{}; 100 | base_station_container* base_stations_{}; 101 | 102 | std::shared_ptr RL; 103 | std::vector total_times_; 104 | }; 105 | 106 | 107 | } // namespace okec 108 | 109 | #endif // OKEC_DQN_DECISION_ENGINE_H_ -------------------------------------------------------------------------------- /include/okec/common/awaitable.h: -------------------------------------------------------------------------------- 1 | /////////////////////////////////////////////////////////////////////////////// 2 | // __ __ _ ____ ___ 3 | // / \( / )( __)/ __) OKEC(a.k.a. EdgeSim++) 4 | // ( O )) ( ) _)( (__ version 1.0.1 5 | // \__/(__\_)(____)\___) https://github.com/dxnu/okec 6 | // 7 | // Copyright (C) 2023-2024 Gaoxing Li 8 | // Licenced under Apache-2.0 license. See LICENSE.txt for details. 9 | /////////////////////////////////////////////////////////////////////////////// 10 | 11 | #ifndef OKEC_AWAITABLE_H_ 12 | #define OKEC_AWAITABLE_H_ 13 | 14 | #include 15 | #include 16 | 17 | 18 | namespace okec { 19 | 20 | class client_device; 21 | class simulator; 22 | 23 | 24 | class awaitable_promise_base { 25 | public: 26 | auto initial_suspend() noexcept -> std::suspend_never; 27 | [[nodiscard]] auto final_suspend() noexcept -> std::suspend_always; 28 | 29 | auto unhandled_exception() -> void; 30 | auto return_void() -> void; 31 | }; 32 | 33 | 34 | class awaitable { 35 | public: 36 | struct promise_type : awaitable_promise_base { 37 | [[nodiscard]] auto get_return_object() noexcept -> awaitable { 38 | return awaitable { std::coroutine_handle::from_promise(*this) }; 39 | } 40 | }; 41 | 42 | awaitable() = default; 43 | awaitable(awaitable&& other) noexcept; 44 | awaitable& operator=(awaitable&& other) noexcept; 45 | ~awaitable(); 46 | 47 | void resume(); 48 | 49 | // void start(); 50 | 51 | private: 52 | std::coroutine_handle handle_ = nullptr; 53 | 54 | explicit(true) awaitable(std::coroutine_handle handle) noexcept; 55 | awaitable(const awaitable&) = delete; 56 | awaitable& operator=(const awaitable&) = delete; 57 | }; 58 | 59 | class response_awaiter { 60 | public: 61 | response_awaiter(simulator& sim, std::string client_address); 62 | auto await_ready() noexcept -> bool; 63 | auto await_suspend(std::coroutine_handle<> handle) noexcept -> void; 64 | [[nodiscard]] auto await_resume() noexcept -> response; 65 | 66 | private: 67 | simulator& sim; 68 | std::string client_address; 69 | response r; 70 | }; 71 | 72 | auto co_spawn(okec::simulator& ctx, okec::awaitable a) -> void; 73 | 74 | } // namespace okec 75 | 76 | #endif // OKEC_AWAITABLE_H_ -------------------------------------------------------------------------------- /include/okec/common/message.h: -------------------------------------------------------------------------------- 1 | /////////////////////////////////////////////////////////////////////////////// 2 | // __ __ _ ____ ___ 3 | // / \( / )( __)/ __) OKEC(a.k.a. EdgeSim++) 4 | // ( O )) ( ) _)( (__ version 1.0.1 5 | // \__/(__\_)(____)\___) https://github.com/dxnu/okec 6 | // 7 | // Copyright (C) 2023-2024 Gaoxing Li 8 | // Licenced under Apache-2.0 license. See LICENSE.txt for details. 9 | /////////////////////////////////////////////////////////////////////////////// 10 | 11 | #ifndef OKEC_MESSAGE_H_ 12 | #define OKEC_MESSAGE_H_ 13 | 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | 21 | using json = nlohmann::json; 22 | 23 | 24 | namespace okec 25 | { 26 | 27 | 28 | class message { 29 | public: 30 | message() = default; 31 | message(ns3::Ptr packet); 32 | message(std::initializer_list> values); 33 | message(const message& other); 34 | message& operator=(message other) noexcept; 35 | friend void swap(message& lhs, message& rhs) noexcept; 36 | 37 | auto attribute(std::string_view key, std::string_view value) -> void; 38 | auto get_value(std::string_view key) -> std::string; 39 | 40 | auto dump() -> std::string; 41 | 42 | auto type(std::string_view sv) -> void; 43 | auto type() -> std::string; 44 | 45 | auto to_packet() -> ns3::Ptr; 46 | 47 | static auto from_packet(ns3::Ptr packet) -> message; 48 | 49 | auto content(const task& t) -> void; 50 | 51 | auto content(const task_element& item) -> void; 52 | 53 | auto content(const resource& r) -> void; 54 | 55 | auto get_task_element() -> task_element; 56 | 57 | template 58 | auto content() -> Type { 59 | Type result{}; 60 | if (j_.contains("content")) 61 | result = j_["content"].get(); 62 | 63 | return result; 64 | } 65 | 66 | operator json&() { return j_; } 67 | 68 | auto valid() -> bool; 69 | 70 | private: 71 | json j_; 72 | }; 73 | 74 | 75 | inline constexpr std::string_view message_resource_changed { "resource_changed" }; 76 | inline constexpr std::string_view message_response { "response" }; 77 | inline constexpr std::string_view message_handling { "handling" }; 78 | inline constexpr std::string_view message_dispatching { "dispatching" }; 79 | inline constexpr std::string_view message_get_resource_information { "get_resource_information" }; 80 | inline constexpr std::string_view message_resource_information { "resource_information" }; 81 | inline constexpr std::string_view message_decision { "decision" }; 82 | inline constexpr std::string_view message_conflict { "conflict" }; 83 | // inline constexpr std::string_view 84 | 85 | } // namespace okec 86 | 87 | #endif // OKEC_MESSAGE_H_ -------------------------------------------------------------------------------- /include/okec/common/message_handler.hpp: -------------------------------------------------------------------------------- 1 | /////////////////////////////////////////////////////////////////////////////// 2 | // __ __ _ ____ ___ 3 | // / \( / )( __)/ __) OKEC(a.k.a. EdgeSim++) 4 | // ( O )) ( ) _)( (__ version 1.0.1 5 | // \__/(__\_)(____)\___) https://github.com/dxnu/okec 6 | // 7 | // Copyright (C) 2023-2024 Gaoxing Li 8 | // Licenced under Apache-2.0 license. See LICENSE.txt for details. 9 | /////////////////////////////////////////////////////////////////////////////// 10 | 11 | #ifndef OKEC_MESSAGE_HANDLER_H_ 12 | #define OKEC_MESSAGE_HANDLER_H_ 13 | 14 | #include 15 | #include 16 | #include 17 | 18 | 19 | namespace okec 20 | { 21 | 22 | template > 23 | class message_handler { 24 | using delegate_type = utils::delegate; 25 | 26 | public: 27 | auto add_handler(std::string_view msg_type, CallbackType callback) -> void { 28 | delegate_.insert(msg_type, callback); 29 | } 30 | 31 | template 32 | auto dispatch(const std::string& msg_type, Args... args) -> bool { 33 | typename delegate_type::value_type::const_iterator iter; 34 | bool ret = delegate_.find(msg_type, iter); 35 | if (ret) { 36 | iter->second(args...); 37 | } 38 | 39 | return ret; 40 | } 41 | 42 | private: 43 | delegate_type delegate_; 44 | }; 45 | 46 | 47 | } // namespace okec 48 | 49 | #endif // OKEC_MESSAGE_HANDLER_H_ -------------------------------------------------------------------------------- /include/okec/common/resource.h: -------------------------------------------------------------------------------- 1 | /////////////////////////////////////////////////////////////////////////////// 2 | // __ __ _ ____ ___ 3 | // / \( / )( __)/ __) OKEC(a.k.a. EdgeSim++) 4 | // ( O )) ( ) _)( (__ version 1.0.1 5 | // \__/(__\_)(____)\___) https://github.com/dxnu/okec 6 | // 7 | // Copyright (C) 2023-2024 Gaoxing Li 8 | // Licenced under Apache-2.0 license. See LICENSE.txt for details. 9 | /////////////////////////////////////////////////////////////////////////////// 10 | 11 | #ifndef OKEC_RESOURCE_H_ 12 | #define OKEC_RESOURCE_H_ 13 | 14 | #include 15 | #include 16 | #include 17 | 18 | 19 | 20 | namespace okec 21 | { 22 | 23 | 24 | class resource : public ns3::Object 25 | { 26 | public: 27 | // [address, key, old_value, new_value] 28 | using monitor_type = std::function; 29 | 30 | public: 31 | 32 | static auto GetTypeId() -> ns3::TypeId; 33 | 34 | auto install(ns3::Ptr node) -> void; 35 | 36 | /////////////////////////////////// 37 | resource() = default; 38 | resource(json item) noexcept; 39 | 40 | auto attribute(std::string_view key, std::string_view value) -> void; 41 | 42 | auto reset_value(std::string_view key, std::string_view value) -> std::string; 43 | 44 | auto set_monitor(monitor_type monitor) -> void; 45 | 46 | auto get_value(std::string_view key) const -> std::string; 47 | 48 | auto get_address() -> ns3::Ipv4Address; 49 | 50 | auto dump(const int indent = -1) -> std::string; 51 | 52 | auto begin() const { 53 | return this->empty() ? json::const_iterator() : j_["resource"].begin(); 54 | } 55 | 56 | auto end() const { 57 | return this->empty() ? json::const_iterator() : j_["resource"].end(); 58 | } 59 | 60 | auto empty() const -> bool; 61 | 62 | auto j_data() const -> json; 63 | 64 | auto set_data(json item) -> bool; 65 | 66 | static auto from_msg_packet(ns3::Ptr packet) -> resource; 67 | 68 | private: 69 | json j_; 70 | monitor_type monitor_; 71 | ns3::Ptr node_; 72 | }; 73 | 74 | 75 | // factory function 76 | auto make_resource() -> ns3::Ptr; 77 | 78 | 79 | class resource_container 80 | { 81 | public: 82 | resource_container(std::size_t n); 83 | 84 | auto operator[](std::size_t index) -> ns3::Ptr; 85 | auto operator()(std::size_t index) -> ns3::Ptr; 86 | 87 | auto get(std::size_t index) -> ns3::Ptr; 88 | 89 | auto initialize(std::function)> fn) -> void; 90 | 91 | auto size() const -> std::size_t; 92 | 93 | auto begin() { 94 | return m_resources.begin(); 95 | } 96 | 97 | auto end() { 98 | return m_resources.end(); 99 | } 100 | 101 | auto cbegin() const { 102 | return m_resources.cbegin(); 103 | } 104 | 105 | auto cend() const { 106 | return m_resources.cend(); 107 | } 108 | 109 | auto print(std::string title = "Resource Info" ) -> void; 110 | 111 | auto trace_resource() -> void; 112 | 113 | auto save_to_file(const std::string& file) -> void; 114 | auto load_from_file(const std::string& file) -> bool; 115 | 116 | auto set_monitor(resource::monitor_type monitor) -> void; 117 | 118 | private: 119 | std::vector> m_resources; 120 | }; 121 | 122 | } // namespace okec 123 | 124 | #endif // OKEC_RESOURCE_H_ -------------------------------------------------------------------------------- /include/okec/common/response.h: -------------------------------------------------------------------------------- 1 | /////////////////////////////////////////////////////////////////////////////// 2 | // __ __ _ ____ ___ 3 | // / \( / )( __)/ __) OKEC(a.k.a. EdgeSim++) 4 | // ( O )) ( ) _)( (__ version 1.0.1 5 | // \__/(__\_)(____)\___) https://github.com/dxnu/okec 6 | // 7 | // Copyright (C) 2023-2024 Gaoxing Li 8 | // Licenced under Apache-2.0 license. See LICENSE.txt for details. 9 | /////////////////////////////////////////////////////////////////////////////// 10 | 11 | #ifndef OKEC_RESPONSE_H_ 12 | #define OKEC_RESPONSE_H_ 13 | 14 | #include 15 | #include 16 | #include 17 | 18 | 19 | namespace okec 20 | { 21 | 22 | class response { 23 | public: 24 | using attribute_type = std::pair; 25 | using attributes_type = std::initializer_list; 26 | using value_type = json; 27 | using iterator = json::iterator; 28 | using unary_predicate_type = std::function; 29 | using binary_predicate_type = std::function; 30 | 31 | public: 32 | // auto attribute(std::string_view key, std::string_view value) -> void; 33 | response() = default; 34 | response(const response& other) noexcept; 35 | response& operator=(const response& other) noexcept; 36 | response(response&& other) noexcept; 37 | response& operator=(response&& other) noexcept; 38 | 39 | auto begin() -> iterator; 40 | auto end() -> iterator; 41 | 42 | auto dump(int indent = -1) -> std::string; 43 | 44 | auto data() const { 45 | return j_["response"]["items"]; 46 | } 47 | 48 | auto view() -> value_type&; 49 | 50 | auto size() const -> std::size_t; 51 | 52 | auto emplace_back(attributes_type values) -> void; 53 | // auto emplace_back(attribute_type value) -> void; 54 | 55 | auto find_if(unary_predicate_type pred) -> iterator; 56 | auto count_if(unary_predicate_type pred) const -> int; 57 | auto dump_with(unary_predicate_type pred) -> response; 58 | 59 | auto dump_with(attributes_type values) -> response; 60 | auto dump_with(attribute_type value) -> response; 61 | 62 | private: 63 | auto emplace_back(json item) -> void; 64 | 65 | private: 66 | json j_; 67 | }; 68 | 69 | 70 | } // namespace okec 71 | 72 | #endif // OKEC_RESPONSE_H_ -------------------------------------------------------------------------------- /include/okec/common/simulator.h: -------------------------------------------------------------------------------- 1 | #ifndef OKEC_SIMULATOR_H_ 2 | #define OKEC_SIMULATOR_H_ 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | namespace okec { 9 | 10 | class response; 11 | 12 | class simulator { 13 | public: 14 | simulator(ns3::Time time = ns3::Seconds(300)); 15 | ~simulator(); 16 | 17 | auto run() -> void; 18 | 19 | auto stop_time(ns3::Time time) -> void; 20 | auto stop_time() const -> ns3::Time; 21 | 22 | auto enable_visualizer() -> void; 23 | 24 | auto submit(const std::string& ip, std::function fn) -> void; 25 | 26 | auto complete(const std::string& ip, response&& r) -> void; 27 | 28 | auto is_valid(const std::string& ip) -> bool; 29 | 30 | auto hold_coro(awaitable a) -> void; 31 | 32 | private: 33 | ns3::Time stop_time_; 34 | std::vector coros_; 35 | std::unordered_map> completion_; 36 | }; 37 | 38 | namespace now { 39 | 40 | inline auto years() -> double { 41 | return ns3::Simulator::Now().GetYears(); 42 | } 43 | 44 | inline auto days() -> double { 45 | return ns3::Simulator::Now().GetDays(); 46 | } 47 | 48 | inline auto hours() -> double { 49 | return ns3::Simulator::Now().GetHours(); 50 | } 51 | 52 | inline auto minutes() -> double { 53 | return ns3::Simulator::Now().GetMinutes(); 54 | } 55 | 56 | inline auto seconds() -> double { 57 | return ns3::Simulator::Now().GetSeconds(); 58 | } 59 | 60 | inline auto milli_seconds() -> double { 61 | return ns3::Simulator::Now().GetMilliSeconds(); 62 | } 63 | 64 | inline auto micro_seconds() -> double { 65 | return ns3::Simulator::Now().GetMicroSeconds(); 66 | } 67 | 68 | inline auto nano_seconds() -> double { 69 | return ns3::Simulator::Now().GetNanoSeconds(); 70 | } 71 | 72 | inline auto pico_seconds() -> double { 73 | return ns3::Simulator::Now().GetPicoSeconds(); 74 | } 75 | 76 | inline auto femto_seconds() -> double { 77 | return ns3::Simulator::Now().GetFemtoSeconds(); 78 | } 79 | 80 | } // namespace now 81 | 82 | } // namespace okec 83 | 84 | #endif // OKEC_SIMULATOR_H_ -------------------------------------------------------------------------------- /include/okec/common/task.h: -------------------------------------------------------------------------------- 1 | /////////////////////////////////////////////////////////////////////////////// 2 | // __ __ _ ____ ___ 3 | // / \( / )( __)/ __) OKEC(a.k.a. EdgeSim++) 4 | // ( O )) ( ) _)( (__ version 1.0.1 5 | // \__/(__\_)(____)\___) https://github.com/dxnu/okec 6 | // 7 | // Copyright (C) 2023-2024 Gaoxing Li 8 | // Licenced under Apache-2.0 license. See LICENSE.txt for details. 9 | /////////////////////////////////////////////////////////////////////////////// 10 | 11 | #ifndef OKEC_TASK_H_ 12 | #define OKEC_TASK_H_ 13 | 14 | #include 15 | #include 16 | 17 | 18 | namespace okec 19 | { 20 | 21 | class task_element 22 | { 23 | public: 24 | task_element(json* item) noexcept; 25 | task_element(json item) noexcept; 26 | task_element(const task_element& other) noexcept; 27 | task_element& operator=(const task_element& other) noexcept; 28 | task_element(task_element&& other) noexcept; 29 | task_element& operator=(task_element&& other) noexcept; 30 | ~task_element(); 31 | 32 | auto get_header(const std::string& key) const -> std::string; 33 | auto set_header(std::string_view key, std::string_view value) -> bool; 34 | 35 | auto get_body(const std::string& key) const -> std::string; 36 | auto set_body(std::string_view key, std::string_view value) -> bool; 37 | 38 | auto j_data() const -> json; 39 | 40 | auto empty() const -> bool; 41 | 42 | static auto from_msg_packet(ns3::Ptr packet) -> task_element; 43 | 44 | auto dump(int indent = -1) const -> std::string; 45 | 46 | private: 47 | json* elem_; 48 | bool is_dynamically_allocated; 49 | }; 50 | 51 | class task : public ns3::SimpleRefCount 52 | { 53 | using attribute_t = std::pair; 54 | using attributes_t = std::initializer_list; 55 | 56 | public: 57 | using task_header = attributes_t; 58 | using task_body = attributes_t; 59 | 60 | public: 61 | task() = default; 62 | task(json other); 63 | 64 | // construct task from packet 65 | static auto from_packet(ns3::Ptr packet) -> task; 66 | 67 | static auto from_msg_packet(ns3::Ptr packet) -> task; 68 | 69 | auto emplace_back(task_header, task_body = {}) -> void; 70 | 71 | auto dump(int indent = -1) const -> std::string; 72 | 73 | auto elements_view() -> std::vector; 74 | auto elements() const -> std::vector; 75 | 76 | auto at(std::size_t index) noexcept -> task_element; 77 | auto at(std::size_t index) const noexcept -> task_element; 78 | 79 | auto data() const -> json; 80 | 81 | auto j_data() const -> json; 82 | 83 | auto is_null() const -> bool; 84 | 85 | auto size() const -> std::size_t; 86 | 87 | auto empty() -> bool; 88 | 89 | auto set_if(attributes_t values, auto f) -> void; 90 | 91 | auto find_if(attributes_t values) -> task; 92 | auto find_if(attribute_t value) -> task; 93 | 94 | auto contains(attributes_t values) -> bool; 95 | auto contains(attribute_t value) -> bool; 96 | 97 | static auto get_header(const json& element, const std::string& key) -> std::string; 98 | static auto get_body(const json& element, const std::string& key) -> std::string; 99 | 100 | static auto unique_id() -> std::string; 101 | 102 | auto save_to_file(const std::string& file_name) -> void; 103 | auto load_from_file(const std::string& file_name) -> bool; 104 | 105 | auto operator[](std::size_t index) noexcept -> task_element; 106 | auto operator[](std::size_t index) const noexcept -> task_element; 107 | 108 | private: 109 | auto push_back(const json& sub) -> void; 110 | 111 | private: 112 | json m_task; 113 | }; 114 | 115 | 116 | } // namespace okec 117 | 118 | #endif // OKEC_TASK_H_ -------------------------------------------------------------------------------- /include/okec/config/config.h: -------------------------------------------------------------------------------- 1 | /////////////////////////////////////////////////////////////////////////////// 2 | // __ __ _ ____ ___ 3 | // / \( / )( __)/ __) OKEC(a.k.a. EdgeSim++) 4 | // ( O )) ( ) _)( (__ version 1.0.1 5 | // \__/(__\_)(____)\___) https://github.com/dxnu/okec 6 | // 7 | // Copyright (C) 2023-2024 Gaoxing Li 8 | // Licenced under Apache-2.0 license. See LICENSE.txt for details. 9 | /////////////////////////////////////////////////////////////////////////////// 10 | 11 | #ifndef OKEC_CONFIG_H_ 12 | #define OKEC_CONFIG_H_ 13 | 14 | namespace okec 15 | { 16 | 17 | inline constexpr uint64_t simulator_stop_time = 300; // in seconds 18 | 19 | } // namespace okec 20 | 21 | #endif // OKEC_CONFIG_H_ -------------------------------------------------------------------------------- /include/okec/devices/base_station.h: -------------------------------------------------------------------------------- 1 | /////////////////////////////////////////////////////////////////////////////// 2 | // __ __ _ ____ ___ 3 | // / \( / )( __)/ __) OKEC(a.k.a. EdgeSim++) 4 | // ( O )) ( ) _)( (__ version 1.0.1 5 | // \__/(__\_)(____)\___) https://github.com/dxnu/okec 6 | // 7 | // Copyright (C) 2023-2024 Gaoxing Li 8 | // Licenced under Apache-2.0 license. See LICENSE.txt for details. 9 | /////////////////////////////////////////////////////////////////////////////// 10 | 11 | #ifndef OKEC_BASE_STATION_H_ 12 | #define OKEC_BASE_STATION_H_ 13 | 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | 24 | namespace okec 25 | { 26 | 27 | class base_station_container; 28 | class simulator; 29 | 30 | template 31 | concept decision_maker_t = requires (T t) { t.make_decision(task_element{nullptr}); }; 32 | 33 | class base_station 34 | { 35 | public: 36 | using callback_type = std::function, const ns3::Address&)>; 37 | using es_callback_type = std::function, const ns3::Address&)>; 38 | 39 | public: 40 | base_station(simulator& sim); 41 | ~base_station(); 42 | auto connect_device(edge_device_container& devices) -> void; 43 | 44 | auto get_address() const -> ns3::Ipv4Address; 45 | auto get_port() const -> uint16_t; 46 | 47 | // 获取包含EdgeDevice在内的所有Nodes 48 | auto get_nodes(ns3::NodeContainer& nodes) -> void; 49 | 50 | auto get_edge_nodes(ns3::NodeContainer& nodes) -> void; 51 | 52 | auto get_node() -> ns3::Ptr; 53 | 54 | auto push_base_stations(base_station_container* base_stations) -> void; 55 | 56 | auto set_request_handler(std::string_view msg_type, callback_type callback) -> void; 57 | 58 | auto set_es_request_handler(std::string_view msg_type, es_callback_type callback) -> void; 59 | 60 | auto set_position(double x, double y, double z) -> void; 61 | 62 | auto set_decision_engine(std::shared_ptr engine) -> void; 63 | 64 | auto get_position() -> ns3::Vector; 65 | 66 | auto get_edge_devices() const -> edge_device_container; 67 | 68 | auto write(ns3::Ptr packet, ns3::Ipv4Address destination, uint16_t port) const -> void; 69 | 70 | auto task_sequence(const task_element& item) -> void; 71 | auto task_sequence(task_element&& item) -> void; 72 | auto task_sequence() -> std::vector&; 73 | auto task_sequence_status() -> std::vector&; 74 | 75 | auto print_task_info() -> void; 76 | 77 | auto handle_next() -> void; 78 | 79 | public: 80 | simulator& sim_; 81 | edge_device_container* m_edge_devices; 82 | ns3::Ptr m_udp_application; 83 | ns3::Ptr m_node; 84 | std::vector m_task_sequence; 85 | std::vector m_task_sequence_status; // 0: 未分发;1:已分发 86 | std::shared_ptr m_decision_engine; 87 | }; 88 | 89 | 90 | class base_station_container 91 | { 92 | public: 93 | using pointer_t = std::shared_ptr; 94 | using callback_type = base_station::callback_type; 95 | using es_callback_type = base_station::es_callback_type; 96 | 97 | public: 98 | base_station_container(simulator& sim, std::size_t n); 99 | 100 | template 101 | auto connect_device(EdgeDeviceContainers&... containers) -> bool { 102 | if (sizeof...(containers) != size()) { 103 | log::error("Error base_station_container::connect_device. Arguments size does not match the container size!"); 104 | return false; 105 | } 106 | 107 | auto iter = std::begin(m_base_stations); 108 | ((*iter++)->connect_device(containers), ...); 109 | return true; 110 | } 111 | 112 | auto operator[](std::size_t index) -> pointer_t; 113 | auto operator()(std::size_t index) -> pointer_t; 114 | 115 | auto get(std::size_t index) -> pointer_t; 116 | 117 | auto begin() { 118 | return m_base_stations.begin(); 119 | } 120 | 121 | auto end() { 122 | return m_base_stations.end(); 123 | } 124 | 125 | auto cbegin() const { 126 | return m_base_stations.cbegin(); 127 | } 128 | 129 | auto cend() const { 130 | return m_base_stations.cend(); 131 | } 132 | 133 | auto size() -> std::size_t; 134 | 135 | auto set_request_handler(std::string_view msg_type, callback_type callback) -> void; 136 | 137 | auto set_es_request_handler(std::string_view msg_type, es_callback_type callback) -> void; 138 | 139 | auto set_decision_engine(std::shared_ptr engine) -> void; 140 | 141 | private: 142 | std::vector m_base_stations; 143 | }; 144 | 145 | } // namespace okec 146 | 147 | #endif // OKEC_BASE_STATION_H_ -------------------------------------------------------------------------------- /include/okec/devices/client_device.h: -------------------------------------------------------------------------------- 1 | /////////////////////////////////////////////////////////////////////////////// 2 | // __ __ _ ____ ___ 3 | // / \( / )( __)/ __) OKEC(a.k.a. EdgeSim++) 4 | // ( O )) ( ) _)( (__ version 1.0.1 5 | // \__/(__\_)(____)\___) https://github.com/dxnu/okec 6 | // 7 | // Copyright (C) 2023-2024 Gaoxing Li 8 | // Licenced under Apache-2.0 license. See LICENSE.txt for details. 9 | /////////////////////////////////////////////////////////////////////////////// 10 | 11 | #ifndef OKEC_CLIENT_DEVICE_H_ 12 | #define OKEC_CLIENT_DEVICE_H_ 13 | 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | 25 | namespace okec 26 | { 27 | 28 | 29 | class udp_application; 30 | class base_station; 31 | class response_awaiter; 32 | class simulator; 33 | 34 | 35 | class client_device : public std::enable_shared_from_this 36 | { 37 | using response_type = response; 38 | using done_callback_t = std::function; 39 | public: 40 | using callback_type = std::function, const ns3::Address&)>; 41 | 42 | public: 43 | client_device(simulator& sim); 44 | 45 | auto get_resource() -> ns3::Ptr; 46 | 47 | // 返回当前设备的IP地址 48 | auto get_address() const -> ns3::Ipv4Address; 49 | 50 | // 返回当前设备的端口号 51 | auto get_port() const -> uint16_t; 52 | 53 | auto get_node() -> ns3::Ptr; 54 | 55 | // 为当前设备安装资源 56 | auto install_resource(ns3::Ptr res) -> void; 57 | 58 | // 发送任务 59 | // 发送时间如果是0s,因为UdpApplication的StartTime也是0s,所以m_socket可能尚未初始化,此时Write将无法发送 60 | auto send(task t) -> void; 61 | 62 | auto async_send(task t) -> std::suspend_never; 63 | 64 | auto async_read() -> response_awaiter; 65 | 66 | auto async_read(done_callback_t fn) -> void; 67 | 68 | auto when_done(response_type res) -> void; 69 | 70 | auto set_position(double x, double y, double z) -> void; 71 | auto get_position() -> ns3::Vector; 72 | 73 | auto set_decision_engine(std::shared_ptr engine) -> void; 74 | 75 | auto set_request_handler(std::string_view msg_type, callback_type callback) -> void; 76 | 77 | auto dispatch(std::string_view msg_type, ns3::Ptr packet, const ns3::Address& address) -> void; 78 | 79 | auto response_cache() -> response_type&; 80 | 81 | auto has_done_callback() -> bool; 82 | auto done_callback(response_type res) -> void; 83 | 84 | auto write(ns3::Ptr packet, ns3::Ipv4Address destination, uint16_t port) const -> void; 85 | 86 | 87 | private: 88 | simulator& sim_; 89 | ns3::Ptr m_node; 90 | ns3::Ptr m_udp_application; 91 | response_type m_response; 92 | done_callback_t m_done_fn; 93 | std::shared_ptr m_decision_engine; 94 | }; 95 | 96 | 97 | 98 | class client_device_container 99 | { 100 | using value_type = client_device; 101 | using pointer_type = std::shared_ptr; 102 | using callback_type = client_device::callback_type; 103 | 104 | public: 105 | // 创建含有n个ClientDevice的容器 106 | client_device_container(simulator& sim, std::size_t n) { 107 | m_devices.reserve(n); 108 | for (std::size_t i = 0; i < n; ++i) 109 | m_devices.emplace_back(std::make_shared(sim)); 110 | } 111 | 112 | // 获取所有Nodes 113 | auto get_nodes(ns3::NodeContainer &nodes) -> void { 114 | for (auto& device : m_devices) 115 | nodes.Add(device->get_node()); 116 | } 117 | 118 | auto begin() -> std::vector::iterator { 119 | return m_devices.begin(); 120 | } 121 | 122 | auto end() -> std::vector::iterator { 123 | return m_devices.end(); 124 | } 125 | 126 | auto operator[](std::size_t index) -> pointer_type; 127 | auto operator()(std::size_t index) -> pointer_type; 128 | 129 | auto get_device(std::size_t index) -> pointer_type; 130 | 131 | auto size() -> std::size_t; 132 | 133 | auto install_resources(resource_container& res, int offset = 0) -> void; 134 | 135 | auto set_decision_engine(std::shared_ptr engine) -> void; 136 | 137 | auto set_request_handler(std::string_view msg_type, callback_type callback) -> void; 138 | 139 | private: 140 | std::vector m_devices; 141 | }; 142 | 143 | 144 | } // namespace okec 145 | 146 | #endif // OKEC_CLIENT_DEVICE_H_ -------------------------------------------------------------------------------- /include/okec/devices/cloud_server.h: -------------------------------------------------------------------------------- 1 | /////////////////////////////////////////////////////////////////////////////// 2 | // __ __ _ ____ ___ 3 | // / \( / )( __)/ __) OKEC(a.k.a. EdgeSim++) 4 | // ( O )) ( ) _)( (__ version 1.0.1 5 | // \__/(__\_)(____)\___) https://github.com/dxnu/okec 6 | // 7 | // Copyright (C) 2023-2024 Gaoxing Li 8 | // Licenced under Apache-2.0 license. See LICENSE.txt for details. 9 | /////////////////////////////////////////////////////////////////////////////// 10 | 11 | #ifndef OKEC_CLOUD_DEVICE_H 12 | #define OKEC_CLOUD_DEVICE_H 13 | 14 | #include 15 | #include 16 | #include 17 | #include "ns3/internet-module.h" 18 | #include "ns3/node-container.h" 19 | 20 | 21 | namespace okec 22 | { 23 | 24 | class simulator; 25 | 26 | class cloud_server { 27 | using callback_type = std::function, const ns3::Address&)>; 28 | 29 | public: 30 | cloud_server(simulator& sim); 31 | 32 | auto get_node() -> ns3::Ptr; 33 | 34 | auto get_nodes(ns3::NodeContainer &nodes) -> void; 35 | 36 | // 返回当前设备的IP地址 37 | auto get_address() const -> ns3::Ipv4Address; 38 | 39 | // 返回当前设备的端口号 40 | auto get_port() const -> uint16_t; 41 | 42 | // 获取当前设备绑定的资源 43 | auto get_resource() -> ns3::Ptr; 44 | 45 | // 为当前设备安装资源 46 | auto install_resource(ns3::Ptr res) -> void; 47 | 48 | auto set_position(double x, double y, double z) -> void; 49 | auto get_position() -> ns3::Vector; 50 | 51 | auto set_request_handler(std::string_view msg_type, callback_type callback) -> void; 52 | 53 | auto write(ns3::Ptr packet, ns3::Ipv4Address destination, uint16_t port) const -> void; 54 | 55 | private: 56 | // 处理请求回调函数 57 | auto on_get_resource_information(ns3::Ptr packet, const ns3::Address& remote_address) -> void; 58 | 59 | private: 60 | simulator& sim_; 61 | ns3::Ptr m_node; 62 | ns3::Ptr m_udp_application; 63 | }; 64 | 65 | 66 | } // namespace okec 67 | 68 | 69 | #endif // OKEC_CLOUD_DEVICE_H -------------------------------------------------------------------------------- /include/okec/devices/edge_device.h: -------------------------------------------------------------------------------- 1 | /////////////////////////////////////////////////////////////////////////////// 2 | // __ __ _ ____ ___ 3 | // / \( / )( __)/ __) OKEC(a.k.a. EdgeSim++) 4 | // ( O )) ( ) _)( (__ version 1.0.1 5 | // \__/(__\_)(____)\___) https://github.com/dxnu/okec 6 | // 7 | // Copyright (C) 2023-2024 Gaoxing Li 8 | // Licenced under Apache-2.0 license. See LICENSE.txt for details. 9 | /////////////////////////////////////////////////////////////////////////////// 10 | 11 | #ifndef OKEC_EDGE_DEVICE_H_ 12 | #define OKEC_EDGE_DEVICE_H_ 13 | 14 | #include 15 | #include 16 | 17 | 18 | namespace okec 19 | { 20 | 21 | class simulator; 22 | class task; 23 | 24 | 25 | class edge_device 26 | { 27 | using callback_type = std::function, const ns3::Address&)>; 28 | 29 | public: 30 | edge_device(simulator& sim); 31 | 32 | // 返回当前设备的IP地址 33 | auto get_address() const -> ns3::Ipv4Address; 34 | 35 | // 返回当前设备的端口号 36 | auto get_port() const -> uint16_t; 37 | 38 | auto get_node() -> ns3::Ptr; 39 | 40 | // 获取当前设备绑定的资源 41 | auto get_resource() -> ns3::Ptr; 42 | 43 | // 为当前设备安装资源 44 | auto install_resource(ns3::Ptr res) -> void; 45 | 46 | auto set_position(double x, double y, double z) -> void; 47 | auto get_position() -> ns3::Vector; 48 | 49 | auto set_request_handler(std::string_view msg_type, callback_type callback) -> void; 50 | 51 | auto write(ns3::Ptr packet, ns3::Ipv4Address destination, uint16_t port) const -> void; 52 | 53 | private: 54 | auto on_get_resource_information(ns3::Ptr packet, const ns3::Address& remote_address) -> void; 55 | 56 | public: 57 | simulator& sim_; 58 | ns3::Ptr m_node; 59 | ns3::Ptr m_udp_application; 60 | }; 61 | 62 | 63 | class edge_device_container 64 | { 65 | using value_type = edge_device; 66 | using pointer_type = std::shared_ptr; 67 | 68 | public: 69 | edge_device_container(simulator& sim, std::size_t n); 70 | 71 | // 获取所有Nodes 72 | auto get_nodes(ns3::NodeContainer &nodes) -> void; 73 | 74 | auto get_device(std::size_t index) -> pointer_type; 75 | 76 | auto begin() -> std::vector::iterator { 77 | return m_devices.begin(); 78 | } 79 | 80 | auto end() -> std::vector::iterator { 81 | return m_devices.end(); 82 | } 83 | 84 | auto size() -> std::size_t; 85 | 86 | auto install_resources(resource_container& res, int offset = 0) -> void; 87 | 88 | private: 89 | std::vector m_devices; 90 | }; 91 | 92 | 93 | } // namespace okec 94 | 95 | #endif // OKEC_EDGE_DEVICE_H_ -------------------------------------------------------------------------------- /include/okec/mobility/ap_sta_mobility.hpp: -------------------------------------------------------------------------------- 1 | #ifndef OKEC_AP_STA_MOBILITY_HPP_ 2 | #define OKEC_AP_STA_MOBILITY_HPP_ 3 | 4 | #include 5 | 6 | 7 | namespace okec 8 | { 9 | 10 | class ap_sta_mobility : public mobility { 11 | public: 12 | ap_sta_mobility() { 13 | mobility_.SetPositionAllocator("ns3::GridPositionAllocator", 14 | "MinX", 15 | ns3::DoubleValue(0.0), 16 | "MinY", 17 | ns3::DoubleValue(0.0), 18 | "DeltaX", 19 | ns3::DoubleValue(5.0), 20 | "DeltaY", 21 | ns3::DoubleValue(10.0), 22 | "GridWidth", 23 | ns3::UintegerValue(100), 24 | "LayoutType", 25 | ns3::StringValue("RowFirst")); 26 | } 27 | 28 | auto install(client_device_container& devices) -> void { 29 | ns3::NodeContainer wifiStaNodes; 30 | devices.get_nodes(wifiStaNodes); 31 | 32 | // 设置节点移动速度范围 33 | ns3::Ptr speedVar = ns3::CreateObject(); 34 | speedVar->SetAttribute("Min", ns3::DoubleValue(5.0)); 35 | speedVar->SetAttribute("Max", ns3::DoubleValue(10.0)); 36 | 37 | mobility_.SetMobilityModel("ns3::RandomWalk2dMobilityModel", 38 | "Bounds", 39 | ns3::RectangleValue(ns3::Rectangle(-100, 100, -100, 100)), 40 | "Speed", 41 | ns3::PointerValue(speedVar)); 42 | 43 | mobility_.Install(wifiStaNodes); 44 | } 45 | 46 | auto install(std::shared_ptr bs) -> void { 47 | mobility_.SetMobilityModel("ns3::ConstantPositionMobilityModel"); 48 | mobility_.Install(bs->get_node()); // ap node 49 | } 50 | 51 | private: 52 | ns3::MobilityHelper mobility_; 53 | }; 54 | 55 | } // namespace okec 56 | 57 | #endif // OKEC_AP_STA_MOBILITY_HPP_ -------------------------------------------------------------------------------- /include/okec/mobility/mobility.hpp: -------------------------------------------------------------------------------- 1 | #ifndef OKEC_MOBILITY_HPP_ 2 | #define OKEC_MOBILITY_HPP_ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include "ns3/ns2-mobility-helper.h" 10 | #include "ns3/mobility-helper.h" 11 | #include "ns3/rectangle.h" 12 | 13 | #include 14 | 15 | 16 | namespace okec 17 | { 18 | 19 | template 20 | struct mobility { 21 | auto install(auto& devices) -> void { 22 | auto& self = *static_cast(this); 23 | self.install(devices); 24 | } 25 | 26 | auto test(client_device_container& clients, std::string filename) -> void { 27 | ns3::NodeContainer wifiStaNodes; 28 | clients.get_nodes(wifiStaNodes); 29 | 30 | if (!std::filesystem::exists(filename)) { 31 | log::error("{} does not exist!(Current working directory:{})", filename, std::filesystem::current_path().string()); 32 | exit(1); 33 | } 34 | 35 | auto start = std::chrono::high_resolution_clock::now(); 36 | okec::println("Loading mobility model from {}...", filename); 37 | 38 | ns3::Ns2MobilityHelper trace(std::move(filename)); 39 | trace.Install(wifiStaNodes.Begin(), wifiStaNodes.End()); 40 | 41 | auto end = std::chrono::high_resolution_clock::now(); 42 | std::chrono::duration duration = end - start; 43 | okec::println("Mobility model loaded in {} seconds.", duration.count()); 44 | } 45 | 46 | auto set_position(std::shared_ptr client, double x, double y, double z) -> void { 47 | client->set_position(x, y, z); 48 | } 49 | 50 | auto set_position(std::shared_ptr bs, double x, double y, double z) -> void { 51 | bs->set_position(x, y, z); 52 | } 53 | 54 | auto set_position(cloud_server& cloud, double x, double y, double z) -> void { 55 | cloud.set_position(x, y, z); 56 | } 57 | }; 58 | 59 | 60 | } // namespace okec 61 | 62 | #endif // OKEC_MOBILITY_HPP_ -------------------------------------------------------------------------------- /include/okec/network/multiple_and_single_LAN_WLAN_network_model.hpp: -------------------------------------------------------------------------------- 1 | /////////////////////////////////////////////////////////////////////////////// 2 | // __ __ _ ____ ___ 3 | // / \( / )( __)/ __) OKEC(a.k.a. EdgeSim++) 4 | // ( O )) ( ) _)( (__ version 1.0.1 5 | // \__/(__\_)(____)\___) https://github.com/dxnu/okec 6 | // 7 | // Copyright (C) 2023-2024 Gaoxing Li 8 | // Licenced under Apache-2.0 license. See LICENSE.txt for details. 9 | /////////////////////////////////////////////////////////////////////////////// 10 | 11 | #ifndef OKEC_MULTIPLE_AND_SINGLE_LAN_WLAN_NETWORK_MODEL_HPP_ 12 | #define OKEC_MULTIPLE_AND_SINGLE_LAN_WLAN_NETWORK_MODEL_HPP_ 13 | 14 | #include "network_model.hpp" 15 | 16 | 17 | namespace okec 18 | { 19 | 20 | struct multiple_and_single_LAN_WLAN_network_model { 21 | 22 | auto network_initializer( 23 | client_device_container& clients, 24 | base_station_container::pointer_t base_station, 25 | ns3::Ipv4AddressHelper& address, 26 | bool routing = true) -> void { 27 | 28 | ns3::NodeContainer p2pNodes; 29 | ns3::NodeContainer edgeNodes; 30 | base_station->get_edge_nodes(edgeNodes); 31 | p2pNodes.Add(base_station->get_node()); 32 | p2pNodes.Add(edgeNodes.Get(0)); 33 | 34 | ns3::PointToPointHelper pointToPoint; 35 | pointToPoint.SetDeviceAttribute("DataRate", ns3::StringValue("5Mbps")); 36 | pointToPoint.SetChannelAttribute("Delay", ns3::StringValue("2ms")); 37 | 38 | ns3::NetDeviceContainer p2pDevices; 39 | p2pDevices = pointToPoint.Install(p2pNodes); 40 | 41 | 42 | ns3::CsmaHelper csma; 43 | csma.SetChannelAttribute("DataRate", ns3::StringValue("100Mbps")); 44 | csma.SetChannelAttribute("Delay", ns3::TimeValue(ns3::NanoSeconds(6560))); 45 | 46 | ns3::NetDeviceContainer csmaDevices; 47 | csmaDevices = csma.Install(edgeNodes); 48 | 49 | ns3::NodeContainer wifiStaNodes; 50 | clients.get_nodes(wifiStaNodes); 51 | ns3::NodeContainer wifiApNode = p2pNodes.Get(0); 52 | 53 | ns3::YansWifiChannelHelper channel = ns3::YansWifiChannelHelper::Default(); 54 | ns3::YansWifiPhyHelper phy; 55 | phy.SetChannel(channel.Create()); 56 | 57 | ns3::WifiMacHelper mac; 58 | ns3::Ssid ssid = ns3::Ssid("ns-3-ssid"); 59 | 60 | ns3::WifiHelper wifi; 61 | 62 | ns3::NetDeviceContainer staDevices; 63 | mac.SetType("ns3::StaWifiMac", "Ssid", ns3::SsidValue(ssid), "ActiveProbing", ns3::BooleanValue(false)); 64 | staDevices = wifi.Install(phy, mac, wifiStaNodes); 65 | 66 | ns3::NetDeviceContainer apDevices; 67 | mac.SetType("ns3::ApWifiMac", "Ssid", ns3::SsidValue(ssid)); 68 | apDevices = wifi.Install(phy, mac, wifiApNode); 69 | //////////////////////////////////////// 70 | ns3::Mac48Address bssid("00:11:22:33:44:55"); // 设置BSSID 71 | ns3::Ptr wifiDevice = ns3::DynamicCast(apDevices.Get(0)); 72 | uint8_t linkId = 0; 73 | wifiDevice->GetMac()->SetBssid(bssid, linkId); 74 | //////////////////////////////////////// 75 | 76 | ns3::MobilityHelper mobility; 77 | 78 | mobility.SetPositionAllocator("ns3::GridPositionAllocator", 79 | "MinX", 80 | ns3::DoubleValue(0.0), 81 | "MinY", 82 | ns3::DoubleValue(0.0), 83 | "DeltaX", 84 | ns3::DoubleValue(5.0), 85 | "DeltaY", 86 | ns3::DoubleValue(10.0), 87 | "GridWidth", 88 | ns3::UintegerValue(3), 89 | "LayoutType", 90 | ns3::StringValue("RowFirst")); 91 | 92 | mobility.SetMobilityModel("ns3::RandomWalk2dMobilityModel", 93 | "Bounds", 94 | ns3::RectangleValue(ns3::Rectangle(-50, 50, -50, 50))); 95 | mobility.Install(wifiStaNodes); 96 | 97 | mobility.SetMobilityModel("ns3::ConstantPositionMobilityModel"); 98 | mobility.Install(wifiApNode); 99 | 100 | ns3::InternetStackHelper stack; 101 | stack.Install(edgeNodes); 102 | stack.Install(wifiApNode); 103 | stack.Install(wifiStaNodes); 104 | 105 | // Initialize addresses. 106 | address.Assign(p2pDevices); 107 | address.NewNetwork(); 108 | 109 | address.Assign(csmaDevices); 110 | address.NewNetwork(); 111 | 112 | address.Assign(staDevices); 113 | address.Assign(apDevices); 114 | address.NewNetwork(); 115 | 116 | if (routing) 117 | ns3::Ipv4GlobalRoutingHelper::PopulateRoutingTables(); 118 | } 119 | 120 | // Set up scenarios with a single base station serving clients from the same network segments 121 | auto network_initializer( 122 | client_device_container& clients, 123 | base_station_container::pointer_t base_station) -> void { 124 | 125 | ns3::Ipv4AddressHelper address; 126 | address.SetBase("10.1.1.0", "255.255.255.0"); 127 | network_initializer(clients, base_station, address); 128 | } 129 | 130 | // Set up scenarios with multiple base stations serving clients from different network segments 131 | auto network_initializer( 132 | std::vector& clients, 133 | base_station_container& base_stations) -> void { 134 | 135 | int APs = base_stations.size(); 136 | if (APs != static_cast(clients.size())) { 137 | log::error("Fatal error! (network_initializer) Client size does not match the BS size!"); 138 | return; 139 | } 140 | 141 | 142 | ns3::Ipv4AddressHelper address; 143 | address.SetBase("10.1.1.0", "255.255.255.0"); 144 | 145 | for (auto i : std::views::iota(0, APs)) { 146 | network_initializer(clients[i], base_stations[i], address, false); 147 | } 148 | 149 | // Connect all base stations 150 | ns3::NodeContainer p2pAPNodes[APs-1]; 151 | for (auto const& indices : std::views::iota(0, APs) | std::views::slide(2)) { 152 | auto it = std::begin(indices); 153 | p2pAPNodes[*it].Add(base_stations[*it]->get_node()); 154 | p2pAPNodes[*it].Add(base_stations[*std::next(it)]->get_node()); 155 | } 156 | 157 | 158 | ns3::PointToPointHelper p2pAPHelper; 159 | p2pAPHelper.SetDeviceAttribute("DataRate", ns3::StringValue("50Mbps")); 160 | p2pAPHelper.SetChannelAttribute("Delay", ns3::StringValue("5ms")); 161 | 162 | ns3::NetDeviceContainer p2pAPDevices[APs-1]; 163 | for (auto i : std::views::iota(0, APs-1)) { 164 | p2pAPDevices[i] = p2pAPHelper.Install(p2pAPNodes[i]); 165 | } 166 | 167 | for (auto i : std::views::iota(0, APs-1)) { 168 | address.Assign(p2pAPDevices[i]); 169 | address.NewNetwork(); 170 | } 171 | 172 | ns3::Ipv4GlobalRoutingHelper::PopulateRoutingTables(); 173 | } 174 | }; 175 | 176 | template<> inline constexpr bool enable_network_model = true; 177 | 178 | } // namespace okec 179 | 180 | 181 | #endif // OKEC_MULTIPLE_AND_SINGLE_LAN_WLAN_NETWORK_MODEL_HPP_ -------------------------------------------------------------------------------- /include/okec/network/udp_application.h: -------------------------------------------------------------------------------- 1 | /////////////////////////////////////////////////////////////////////////////// 2 | // __ __ _ ____ ___ 3 | // / \( / )( __)/ __) OKEC(a.k.a. EdgeSim++) 4 | // ( O )) ( ) _)( (__ version 1.0.1 5 | // \__/(__\_)(____)\___) https://github.com/dxnu/okec 6 | // 7 | // Copyright (C) 2023-2024 Gaoxing Li 8 | // Licenced under Apache-2.0 license. See LICENSE.txt for details. 9 | /////////////////////////////////////////////////////////////////////////////// 10 | 11 | #ifndef OKEC_UDP_APPLICATION_H_ 12 | #define OKEC_UDP_APPLICATION_H_ 13 | 14 | #include 15 | #include 16 | #include 17 | 18 | 19 | namespace okec 20 | { 21 | 22 | class udp_application : public ns3::Application 23 | { 24 | public: 25 | using callback_type = std::function, const ns3::Address&)>; 26 | 27 | public: 28 | udp_application(); 29 | ~udp_application() override; 30 | 31 | static auto GetTypeId() -> ns3::TypeId; 32 | virtual auto GetInstanceTypeId() const -> ns3::TypeId; 33 | 34 | auto read_handler(ns3::Ptr socket) -> void; 35 | auto write(ns3::Ptr packet, ns3::Ipv4Address destination, uint16_t port) -> void; 36 | 37 | auto get_address() -> ns3::Ipv4Address const; 38 | auto get_port() -> u_int16_t const; 39 | 40 | auto set_request_handler(std::string_view msg_type, callback_type callback) -> void; 41 | 42 | auto dispatch(std::string_view msg_type, ns3::Ptr packet, const ns3::Address& address) -> void; 43 | 44 | private: 45 | auto StartApplication() -> void override; 46 | auto StopApplication() -> void override; 47 | 48 | // 获取当前IPv4地址 49 | static auto get_socket_address(ns3::Ptr socket) -> ns3::Ipv4Address; 50 | 51 | private: 52 | uint16_t m_port; 53 | ns3::Ptr m_recv_socket; 54 | ns3::Ptr m_send_socket; 55 | message_handler m_msg_handler; 56 | }; 57 | 58 | 59 | } // namespace okec 60 | 61 | 62 | #endif // OKEC_UDP_APPLICATION_H_ -------------------------------------------------------------------------------- /include/okec/okec.hpp: -------------------------------------------------------------------------------- 1 | /////////////////////////////////////////////////////////////////////////////// 2 | // __ __ _ ____ ___ 3 | // / \( / )( __)/ __) OKEC(a.k.a. EdgeSim++) 4 | // ( O )) ( ) _)( (__ version 1.0.1 5 | // \__/(__\_)(____)\___) https://github.com/dxnu/okec 6 | // 7 | // Copyright (C) 2023-2024 Gaoxing Li 8 | // Licenced under Apache-2.0 license. See LICENSE.txt for details. 9 | /////////////////////////////////////////////////////////////////////////////// 10 | 11 | #ifndef OKEC_HPP_ 12 | #define OKEC_HPP_ 13 | 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | #endif // OKEC_HPP_ -------------------------------------------------------------------------------- /include/okec/utils/delegate.hpp: -------------------------------------------------------------------------------- 1 | /////////////////////////////////////////////////////////////////////////////// 2 | // __ __ _ ____ ___ 3 | // / \( / )( __)/ __) OKEC(a.k.a. EdgeSim++) 4 | // ( O )) ( ) _)( (__ version 1.0.1 5 | // \__/(__\_)(____)\___) https://github.com/dxnu/okec 6 | // 7 | // Copyright (C) 2023-2024 Gaoxing Li 8 | // Licenced under Apache-2.0 license. See LICENSE.txt for details. 9 | /////////////////////////////////////////////////////////////////////////////// 10 | 11 | #ifndef OKEC_DELEGATE_H_ 12 | #define OKEC_DELEGATE_H_ 13 | 14 | #include 15 | 16 | 17 | namespace okec::utils 18 | { 19 | 20 | template 21 | class delegate { 22 | public: 23 | using value_type = std::map; 24 | 25 | 26 | template 27 | auto insert(T&& id, CallbackType callback) -> bool { 28 | return associations_.emplace(typename value_type::value_type{ std::forward(id), callback }).second; 29 | } 30 | 31 | template 32 | auto remove(T&& id) -> bool { 33 | return associations_.erase(std::forward(id)) == 1; 34 | } 35 | 36 | auto clear() -> void { 37 | associations_.clear(); 38 | } 39 | 40 | auto begin() -> typename value_type::const_iterator { 41 | return associations_.cbegin(); 42 | } 43 | 44 | auto end() -> typename value_type::const_iterator { 45 | return associations_.cend(); 46 | } 47 | 48 | template 49 | auto find(T&& id, typename value_type::const_iterator& iter) -> bool { 50 | iter = associations_.find(std::forward(id)); 51 | if (iter != associations_.end()) 52 | return true; 53 | 54 | return false; 55 | } 56 | 57 | private: 58 | value_type associations_; 59 | }; 60 | 61 | 62 | } // namespace okec::utils 63 | 64 | #endif // OKEC_DELEGATE_H_ -------------------------------------------------------------------------------- /include/okec/utils/format_helper.hpp: -------------------------------------------------------------------------------- 1 | /////////////////////////////////////////////////////////////////////////////// 2 | // __ __ _ ____ ___ 3 | // / \( / )( __)/ __) OKEC(a.k.a. EdgeSim++) 4 | // ( O )) ( ) _)( (__ version 1.0.1 5 | // \__/(__\_)(____)\___) https://github.com/dxnu/okec 6 | // 7 | // Copyright (C) 2023-2024 Gaoxing Li 8 | // Licenced under Apache-2.0 license. See LICENSE.txt for details. 9 | /////////////////////////////////////////////////////////////////////////////// 10 | 11 | #ifndef OKEC_FORMAT_HELPER_HPP_ 12 | #define OKEC_FORMAT_HELPER_HPP_ 13 | 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | 23 | namespace okec { 24 | 25 | template 26 | auto unmove(T&& x) -> const T& { 27 | return x; 28 | } 29 | 30 | template 31 | inline auto format(std::format_string&& fmt, Args&&... args) 32 | -> std::string { 33 | return std::format(std::forward>(fmt), std::forward(args)...); 34 | } 35 | 36 | template 37 | inline auto print(std::format_string&& fmt, Args&&... args) 38 | -> void { 39 | std::cout << okec::format(std::forward>(fmt), std::forward(args)...); 40 | } 41 | 42 | template 43 | inline auto println(std::format_string&& fmt, Args&&... args) 44 | -> void { 45 | print(std::forward>(fmt), std::forward(args)...); 46 | std::cout << '\n'; 47 | } 48 | 49 | } // namespace okec 50 | 51 | 52 | // formatting Ipv4Address 53 | template <> 54 | struct std::formatter { 55 | constexpr auto parse(format_parse_context& ctx) { 56 | auto it = ctx.begin(), end = ctx.end(); 57 | if (it != end && (*it == 'i' && *(++it) == 'p')) it++; 58 | if (it != end && *it != '}') throw std::format_error("invalid format"); 59 | return it; 60 | } 61 | 62 | template 63 | auto format(const ns3::Ipv4Address& ipv4Address, FormatContext& ctx) const { 64 | std::ostringstream oss; 65 | uint32_t address = ipv4Address.Get(); 66 | oss << ((address >> 24) & 0xff) << "." << ((address >> 16) & 0xff) << "." 67 | << ((address >> 8) & 0xff) << "." << ((address >> 0) & 0xff); 68 | return std::vformat_to(ctx.out(), "{}", std::make_format_args(okec::unmove(oss.str()))); 69 | } 70 | }; 71 | 72 | 73 | // formatting okec::task 74 | template <> 75 | struct std::formatter { 76 | constexpr auto parse(format_parse_context& ctx) { 77 | auto it = ctx.begin(), end = ctx.end(); 78 | if (it != end && *it == 't') it++; 79 | if (it != end && *it != '}') throw std::format_error("invalid task format"); 80 | return it; 81 | } 82 | 83 | template 84 | auto format(const okec::task& t, FormatContext& ctx) const { 85 | int index = 1; 86 | std::string info; 87 | for (const auto& item : t.data()) 88 | { 89 | info += std::vformat("[{:>{}}] ", std::make_format_args( 90 | okec::unmove(index++), okec::unmove(std::to_string(t.size()).length()))); 91 | 92 | if (item.contains("/header"_json_pointer)) 93 | { 94 | for (auto it = item["header"].begin(); it != item["header"].end(); ++it) 95 | { 96 | info += std::vformat("{}: {} ", std::make_format_args( 97 | it.key(), okec::unmove(it.value().template get()))); 98 | } 99 | } 100 | 101 | if (item.contains("/body"_json_pointer)) 102 | { 103 | for (auto it = item["body"].begin(); it != item["body"].end(); ++it) 104 | { 105 | info += std::vformat("{}: {} ", std::make_format_args( 106 | it.key(), okec::unmove(it.value().template get()))); 107 | } 108 | } 109 | info += "\n"; 110 | } 111 | 112 | return std::vformat_to(ctx.out(), "{}", std::make_format_args(info)); 113 | } 114 | }; 115 | 116 | template <> 117 | struct std::formatter { 118 | constexpr auto parse(format_parse_context& ctx) { 119 | auto it = ctx.begin(), end = ctx.end(); 120 | if (it != end && (*it == 'r' && *(++it) == 's')) it++; 121 | if (it != end && *it != '}') throw std::format_error("invalid resource format"); 122 | return it; 123 | } 124 | 125 | template 126 | auto format(const okec::resource_container& rs, FormatContext& ctx) const { 127 | int index = 1; 128 | std::string info; 129 | for (auto item = rs.cbegin(); item != rs.cend(); ++item) { 130 | info += std::vformat("[{:>{}}] ", std::make_format_args( 131 | okec::unmove(index++), okec::unmove(std::to_string(rs.size()).length()))); 132 | for (auto it = (*item)->begin(); it != (*item)->end(); ++it) 133 | { 134 | info += std::vformat("{}: {} ", std::make_format_args( 135 | it.key(), okec::unmove(it.value().template get()))); 136 | } 137 | 138 | info += "\n"; 139 | } 140 | 141 | return std::vformat_to(ctx.out(), "{}", std::make_format_args(info)); 142 | } 143 | }; 144 | 145 | template <> 146 | struct std::formatter { 147 | constexpr auto parse(format_parse_context& ctx) { 148 | auto it = ctx.begin(), end = ctx.end(); 149 | if (it != end && *it == 'r') it++; 150 | if (it != end && *it != '}') throw std::format_error("invalid response format"); 151 | return it; 152 | } 153 | 154 | template 155 | auto format(const okec::response& r, FormatContext& ctx) const { 156 | int index = 1; 157 | std::string info; 158 | for (const auto& item : r.data()) 159 | { 160 | info += std::vformat("[{:>{}}] ", std::make_format_args( 161 | okec::unmove(index++), okec::unmove(std::to_string(r.size()).length()))); 162 | for (auto it = item.begin(); it != item.end(); ++it) 163 | { 164 | info += std::vformat("{}: {} ", std::make_format_args( 165 | it.key(), okec::unmove(it.value().template get()))); 166 | } 167 | 168 | info += "\n"; 169 | } 170 | 171 | return std::vformat_to(ctx.out(), "{}", std::make_format_args(info)); 172 | } 173 | }; 174 | 175 | 176 | #endif // OKEC_FORMAT_HELPER_HPP_ -------------------------------------------------------------------------------- /include/okec/utils/log.h: -------------------------------------------------------------------------------- 1 | /////////////////////////////////////////////////////////////////////////////// 2 | // __ __ _ ____ ___ 3 | // / \( / )( __)/ __) OKEC(a.k.a. EdgeSim++) 4 | // ( O )) ( ) _)( (__ version 1.0.1 5 | // \__/(__\_)(____)\___) https://github.com/dxnu/okec 6 | // 7 | // Copyright (C) 2023-2024 Gaoxing Li 8 | // Licenced under Apache-2.0 license. See LICENSE.txt for details. 9 | /////////////////////////////////////////////////////////////////////////////// 10 | 11 | #ifndef OKEC_LOG_H_ 12 | #define OKEC_LOG_H_ 13 | 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | 23 | namespace okec::log { 24 | 25 | enum class level : uint8_t { 26 | debug = 1 << 0, 27 | info = 1 << 1, 28 | warning = 1 << 2, 29 | success = 1 << 3, 30 | error = 1 << 4, 31 | all = debug | info | warning | success | error 32 | }; 33 | 34 | inline constinit bool level_debug_enabled = false; 35 | inline constinit bool level_info_enabled = false; 36 | inline constinit bool level_warning_enabled = false; 37 | inline constinit bool level_success_enabled = false; 38 | inline constinit bool level_error_enabled = false; 39 | 40 | inline auto set_level(level log_level, bool enabled = true) -> void { 41 | if (enabled) { 42 | level_debug_enabled |= std::to_underlying(log_level) & std::to_underlying(level::debug); 43 | level_info_enabled |= std::to_underlying(log_level) & std::to_underlying(level::info); 44 | level_warning_enabled |= std::to_underlying(log_level) & std::to_underlying(level::warning); 45 | level_success_enabled |= std::to_underlying(log_level) & std::to_underlying(level::success); 46 | level_error_enabled |= std::to_underlying(log_level) & std::to_underlying(level::error); 47 | } else { 48 | level_debug_enabled &= ~(std::to_underlying(log_level) & std::to_underlying(level::debug)); 49 | level_info_enabled &= ~(std::to_underlying(log_level) & std::to_underlying(level::info)); 50 | level_warning_enabled &= ~(std::to_underlying(log_level) & std::to_underlying(level::warning)); 51 | level_success_enabled &= ~(std::to_underlying(log_level) & std::to_underlying(level::success)); 52 | level_error_enabled &= ~(std::to_underlying(log_level) & std::to_underlying(level::error)); 53 | } 54 | } 55 | 56 | inline auto operator|(level lhs, level rhs) -> level { 57 | return static_cast(std::to_underlying(lhs) | std::to_underlying(rhs)); 58 | } 59 | 60 | 61 | namespace detail { 62 | 63 | inline auto print(okec::color c, std::string_view content) -> void { 64 | std::cout << fg(c) << content << end_color(); 65 | } 66 | 67 | template 68 | inline auto print(okec::color text_color, std::format_string&& fmt, Args&&... args) 69 | -> void { 70 | constexpr std::string_view time_format = "[+{:.8f}s] "; 71 | constexpr std::string_view solid_square_format = "\u2588 "; 72 | auto indent = std::formatted_size(time_format, okec::now::seconds()) + 73 | std::formatted_size(solid_square_format); 74 | print(okec::color::gray, std::format(time_format, okec::now::seconds())); 75 | print(text_color, solid_square_format); 76 | 77 | auto content = std::format(std::forward>(fmt), std::forward(args)...); 78 | auto winsize = okec::get_winsize(); 79 | if (winsize.col > indent) { 80 | auto data = content 81 | | std::views::chunk(winsize.col - indent) 82 | | std::views::join_with(std::format("\n{:{}}", "", indent - 1)) 83 | | std::views::common; 84 | print(text_color, std::format("{}\n", std::string(data.begin(), data.end()))); 85 | } else { 86 | print(text_color, "{}\n", content); 87 | } 88 | } 89 | 90 | } // namespace detail 91 | 92 | template 93 | inline auto debug(std::format_string&& fmt, Args&&... args) 94 | -> void { 95 | if (level_debug_enabled) 96 | detail::print(okec::color::debug, std::forward>(fmt), std::forward(args)...); 97 | } 98 | 99 | template 100 | inline auto info(std::format_string&& fmt, Args&&... args) 101 | -> void { 102 | if (level_info_enabled) 103 | detail::print(okec::color::info, std::forward>(fmt), std::forward(args)...); 104 | } 105 | 106 | template 107 | inline auto warning(std::format_string&& fmt, Args&&... args) 108 | -> void { 109 | if (level_warning_enabled) 110 | detail::print(okec::color::warning, std::forward>(fmt), std::forward(args)...); 111 | } 112 | 113 | template 114 | inline auto success(std::format_string&& fmt, Args&&... args) 115 | -> void { 116 | if (level_success_enabled) 117 | detail::print(okec::color::success, std::forward>(fmt), std::forward(args)...); 118 | } 119 | 120 | template 121 | inline auto error(std::format_string&& fmt, Args&&... args) 122 | -> void { 123 | if (level_error_enabled) 124 | detail::print(okec::color::error, std::forward>(fmt), std::forward(args)...); 125 | } 126 | 127 | 128 | inline auto indent_size() -> std::size_t { 129 | constexpr std::string_view time_format = "[+{:.8f}s] "; 130 | constexpr std::string_view solid_square_format = "\u2588 "; 131 | return std::formatted_size(time_format, ns3::Simulator::Now().GetSeconds()) + 132 | std::formatted_size(solid_square_format);; 133 | } 134 | 135 | } // namespace okec::log 136 | 137 | #endif // OKEC_LOG_H_ -------------------------------------------------------------------------------- /include/okec/utils/message_helper.hpp: -------------------------------------------------------------------------------- 1 | /////////////////////////////////////////////////////////////////////////////// 2 | // __ __ _ ____ ___ 3 | // / \( / )( __)/ __) OKEC(a.k.a. EdgeSim++) 4 | // ( O )) ( ) _)( (__ version 1.0.1 5 | // \__/(__\_)(____)\___) https://github.com/dxnu/okec 6 | // 7 | // Copyright (C) 2023-2024 Gaoxing Li 8 | // Licenced under Apache-2.0 license. See LICENSE.txt for details. 9 | /////////////////////////////////////////////////////////////////////////////// 10 | 11 | #ifndef OKEC_MESSAGE_HELPER_HPP_ 12 | #define OKEC_MESSAGE_HELPER_HPP_ 13 | 14 | #include 15 | #include 16 | 17 | 18 | namespace okec 19 | { 20 | 21 | 22 | static inline auto get_message_type(ns3::Ptr packet) { 23 | std::string result{}; 24 | json j = packet_helper::to_json(packet); 25 | if (!j.is_null() && j.contains("msgtype")) { 26 | result = j["msgtype"].get(); 27 | } 28 | 29 | return result; 30 | } 31 | 32 | 33 | } // namespace okec 34 | 35 | #endif // OKEC_MESSAGE_HELPER_HPP_ -------------------------------------------------------------------------------- /include/okec/utils/packet_helper.h: -------------------------------------------------------------------------------- 1 | /////////////////////////////////////////////////////////////////////////////// 2 | // __ __ _ ____ ___ 3 | // / \( / )( __)/ __) OKEC(a.k.a. EdgeSim++) 4 | // ( O )) ( ) _)( (__ version 1.0.1 5 | // \__/(__\_)(____)\___) https://github.com/dxnu/okec 6 | // 7 | // Copyright (C) 2023-2024 Gaoxing Li 8 | // Licenced under Apache-2.0 license. See LICENSE.txt for details. 9 | /////////////////////////////////////////////////////////////////////////////// 10 | 11 | #ifndef OKEC_PACKET_HELPER_H_ 12 | #define OKEC_PACKET_HELPER_H_ 13 | 14 | #include 15 | #include 16 | #include 17 | 18 | using json = nlohmann::json; 19 | 20 | namespace okec { 21 | 22 | class task; 23 | class response; 24 | 25 | namespace packet_helper { 26 | 27 | auto make_packet(std::string_view sv) -> ns3::Ptr; 28 | 29 | // convert packet to string 30 | auto to_string(ns3::Ptr packet) -> std::string; 31 | 32 | // 33 | auto to_json(ns3::Ptr packet) -> json; 34 | 35 | 36 | } // namespace packet_helper 37 | } // namespace okec 38 | 39 | #endif // OKEC_PACKET_HELPER_H_ -------------------------------------------------------------------------------- /include/okec/utils/random.hpp: -------------------------------------------------------------------------------- 1 | #ifndef OKEC_RANDOM_HPP_ 2 | #define OKEC_RANDOM_HPP_ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | namespace okec 10 | { 11 | 12 | template 13 | struct rand_range_impl { 14 | auto operator()(T low, T high) -> T { 15 | return torch::rand({1}).uniform_(low, high).template item(); 16 | } 17 | }; 18 | 19 | template <> 20 | struct rand_range_impl { 21 | auto operator()(int low, int high) -> int { 22 | return torch::randint(low, high, {1}).template item(); 23 | } 24 | }; 25 | 26 | // template 27 | // auto rand_range(T low, T high) -> T { 28 | // return rand_range_impl()(low, high); 29 | // } 30 | 31 | template 32 | struct rand_range { 33 | rand_range(T low, T high) 34 | : val{ rand_range_impl()(low, high) } {} 35 | 36 | operator T() const { 37 | return val; 38 | } 39 | 40 | auto to_string(int precision = 2) -> std::string { 41 | if constexpr (std::is_floating_point_v) { 42 | return okec::format("{:.{}f}", val, precision); 43 | } 44 | 45 | return okec::format("{}", val); 46 | } 47 | 48 | private: 49 | T val; 50 | }; 51 | 52 | template 53 | auto rand_value_impl() -> T { 54 | std::random_device rd; 55 | std::mt19937 gen(rd()); 56 | if constexpr (std::is_floating_point_v) { 57 | std::uniform_real_distribution dis; 58 | return dis(gen); 59 | } else { 60 | std::uniform_int_distribution dis; 61 | return dis(gen); 62 | } 63 | } 64 | 65 | template 66 | requires std::is_floating_point_v> 67 | || std::is_integral_v> 68 | class rand_value { 69 | using value_type = std::remove_cvref_t; 70 | 71 | public: 72 | rand_value() 73 | : val{ rand_value_impl() } {} 74 | 75 | operator value_type() const { 76 | return val; 77 | } 78 | 79 | auto to_string(int precision = 2) -> std::string { 80 | if constexpr (std::is_floating_point_v) { 81 | return okec::format("{:.{}f}", val, precision); 82 | } 83 | 84 | return okec::format("{}", val); 85 | } 86 | 87 | private: 88 | value_type val; 89 | }; 90 | 91 | inline double rand_rayleigh(double scale = 1.0) { 92 | static std::random_device rd; 93 | static std::mt19937 gen(rd()); 94 | 95 | // Create a normal distribution with mean 0 and standard deviation 1 96 | static std::normal_distribution distribution(0.0, 1.0); 97 | 98 | // Generate two independent standard normal random variables 99 | double x = distribution(gen); 100 | double y = distribution(gen); 101 | 102 | // Use the Rayleigh distribution formula: sigma * sqrt(X^2 + Y^2) 103 | return scale * std::sqrt(x * x + y * y); 104 | } 105 | 106 | } // namespace okec 107 | 108 | #endif // OKEC_RANDOM_HPP_ -------------------------------------------------------------------------------- /include/okec/utils/read_csv.h: -------------------------------------------------------------------------------- 1 | /////////////////////////////////////////////////////////////////////////////// 2 | // __ __ _ ____ ___ 3 | // / \( / )( __)/ __) OKEC(a.k.a. EdgeSim++) 4 | // ( O )) ( ) _)( (__ version 1.0.1 5 | // \__/(__\_)(____)\___) https://github.com/dxnu/okec 6 | // 7 | // Copyright (C) 2023-2024 Gaoxing Li 8 | // Licenced under Apache-2.0 license. See LICENSE.txt for details. 9 | /////////////////////////////////////////////////////////////////////////////// 10 | 11 | #ifndef OKEC_READ_CSV_H_ 12 | #define OKEC_READ_CSV_H_ 13 | 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | 20 | namespace okec 21 | { 22 | 23 | using dataset_sequence_type = std::vector>; 24 | 25 | auto read_csv(std::string_view file, std::string_view type = "", std::string_view delimiter = ",") 26 | -> std::optional; 27 | 28 | } // namespace okec 29 | 30 | 31 | #endif // OKEC_READ_CSV_H_ -------------------------------------------------------------------------------- /include/okec/utils/singleton.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | MIT License 4 | 5 | Copyright (c) 2020 lkimuk(Gaoxing Li) 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a copy 8 | of this software and associated documentation files (the "Software"), to deal 9 | in the Software without restriction, including without limitation the rights 10 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | copies of the Software, and to permit persons to whom the Software is 12 | furnished to do so, subject to the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be included in all 15 | copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | SOFTWARE. 24 | */ 25 | 26 | // This implementation copies from okdp design pattern library. 27 | 28 | #ifndef OKEC_SINGLETON_HPP_ 29 | #define OKEC_SINGLETON_HPP_ 30 | 31 | namespace okec::utils 32 | { 33 | 34 | 35 | template 36 | class singleton 37 | { 38 | public: 39 | 40 | template 41 | static T& instance(Args&&... args) { 42 | static T obj(std::forward(args)...); 43 | return obj; 44 | } 45 | 46 | protected: 47 | singleton() = default; 48 | virtual ~singleton() {} 49 | 50 | private: 51 | singleton(const singleton&) = delete; 52 | singleton& operator=(const singleton&) = delete; 53 | singleton(singleton&&) = delete; 54 | singleton& operator=(singleton&&) = delete; 55 | }; 56 | 57 | 58 | } // namespace okec::utils 59 | 60 | #endif // OKDP_SINGLETON_HPP_ -------------------------------------------------------------------------------- /include/okec/utils/sys.h: -------------------------------------------------------------------------------- 1 | /////////////////////////////////////////////////////////////////////////////// 2 | // __ __ _ ____ ___ 3 | // / \( / )( __)/ __) OKEC(a.k.a. EdgeSim++) 4 | // ( O )) ( ) _)( (__ version 1.0.1 5 | // \__/(__\_)(____)\___) https://github.com/dxnu/okec 6 | // 7 | // Copyright (C) 2023-2024 Gaoxing Li 8 | // Licenced under Apache-2.0 license. See LICENSE.txt for details. 9 | /////////////////////////////////////////////////////////////////////////////// 10 | 11 | #ifndef OKEC_SYS_H_ 12 | #define OKEC_SYS_H_ 13 | 14 | 15 | namespace okec { 16 | 17 | struct winsize_t { 18 | unsigned short int row; 19 | unsigned short int col; 20 | // unsigned short int x; 21 | // unsigned short int y; 22 | }; 23 | 24 | auto get_winsize() -> winsize_t; 25 | 26 | 27 | } // namespace okec 28 | 29 | #endif // OKEC_SYS_H_ -------------------------------------------------------------------------------- /include/okec/utils/visualizer.hpp: -------------------------------------------------------------------------------- 1 | /////////////////////////////////////////////////////////////////////////////// 2 | // __ __ _ ____ ___ 3 | // / \( / )( __)/ __) OKEC(a.k.a. EdgeSim++) 4 | // ( O )) ( ) _)( (__ version 1.0.1 5 | // \__/(__\_)(____)\___) https://github.com/dxnu/okec 6 | // 7 | // Copyright (C) 2023-2024 Gaoxing Li 8 | // Licenced under Apache-2.0 license. See LICENSE.txt for details. 9 | /////////////////////////////////////////////////////////////////////////////// 10 | 11 | #ifndef OKEC_VISUALIZER_HPP_ 12 | #define OKEC_VISUALIZER_HPP_ 13 | 14 | 15 | // #include "matplotlibcpp.h" 16 | 17 | 18 | namespace okec 19 | { 20 | // namespace plt = matplotlibcpp; 21 | 22 | template 23 | void draw(const std::vector& list, std::string_view ylabel) { 24 | // plt::plot(list); 25 | // // plt::xlabel("tasks"); 26 | // plt::ylabel(ylabel.data()); 27 | // plt::show(); 28 | } 29 | 30 | // template 31 | // void draw(const std::vector& x_points, const std::vector& y_points, std::string_view xlabel, std::string_view ylabel) { 32 | // plt::plot(x_points, y_points); 33 | // plt::xlabel(xlabel.data()); 34 | // plt::ylabel(ylabel.data()); 35 | // plt::show(); 36 | // } 37 | } 38 | 39 | #endif // OKEC_VISUALIZER_HPP_ -------------------------------------------------------------------------------- /mkdocs.yml: -------------------------------------------------------------------------------- 1 | site_name: OKEC(EdgeSim++) 2 | site_url: https://dxnu.github.io/okec/ 3 | theme: 4 | name: material 5 | # logo: assets/logo.png 6 | # custom_dir: overrides 7 | features: 8 | - navigation.tabs 9 | - navigation.sections 10 | - navigation.top 11 | - navigation.instant 12 | - navigation.instant.prefetch 13 | - navigation.instant.progress 14 | - navigation.tracking 15 | - navigation.tabs 16 | - navigation.tabs.sticky 17 | - navigation.path # sponser only 18 | - toc.follow 19 | # - toc.integrate 20 | # - navigation.tabs 21 | - search.suggest 22 | - search.highlight 23 | - content.tabs.link 24 | - content.code.annotation 25 | - content.code.copy 26 | language: en 27 | palette: 28 | - scheme: default 29 | toggle: 30 | icon: material/toggle-switch-off-outline 31 | name: Switch to dark mode 32 | primary: teal 33 | accent: purple 34 | - scheme: slate 35 | toggle: 36 | icon: material/toggle-switch 37 | name: Switch to light mode 38 | primary: teal 39 | accent: lime 40 | 41 | extra: 42 | social: 43 | - icon: fontawesome/brands/github-alt 44 | link: https://github.com/dxnu 45 | 46 | extra_css: 47 | - stylesheets/extra.css 48 | 49 | markdown_extensions: 50 | - pymdownx.highlight: 51 | anchor_linenums: true 52 | - pymdownx.superfences 53 | - pymdownx.inlinehilite 54 | - pymdownx.snippets 55 | - admonition 56 | - pymdownx.arithmatex: 57 | generic: true 58 | - footnotes 59 | - pymdownx.details 60 | - pymdownx.mark 61 | - attr_list 62 | - pymdownx.emoji: 63 | emoji_index: !!python/name:material.extensions.emoji.twemoji 64 | emoji_generator: !!python/name:material.extensions.emoji.to_svg 65 | 66 | nav: 67 | - Homepage: "index.md" 68 | - Installation: "Installation.md" 69 | - Tutorial: 70 | - Getting started: 71 | - "Formatting Output": "okec/getting-started/formatting.md" 72 | - "Heterogeneous Devices": "okec/getting-started/heterogeneous-devices.md" 73 | - "Log": "okec/getting-started/log.md" 74 | - "Task": "okec/getting-started/task.md" 75 | - "Task Offloading": "okec/getting-started/task-offloading.md" 76 | - "Visualizer": "okec/getting-started/visualizer.md" 77 | - Components: 78 | - Algorithms: 79 | - "BaseStation": "page2.md" 80 | - Common: 81 | - "simulator": "okec/components/common/simulator.md" 82 | - "simulation time": "okec/components/common/simulation-time.md" 83 | - "task": "okec/components/common/task.md" 84 | - Config: 85 | - "BaseStation": "page2.md" 86 | - Devices: 87 | - "BaseStation": "page2.md" 88 | - Network: 89 | - "BaseStation": "page2.md" 90 | - Utils: 91 | - "BaseStation": "page2.md" 92 | - Customization: 93 | - "Customizing tasks": "okec/customization/tasks.md" 94 | - "Customizing resources": "okec/customization/resources.md" 95 | - "Customizing responses": "okec/customization/responses.md" 96 | - "Customizing network models": "okec/customization/network-models.md" 97 | - "Customizing decision engines": "okec/customization/decision-engines.md" 98 | - Miscellaneous: 99 | - Network Models: "network/network-models.md" 100 | - Decision Engines: "algorithms/decision-engines.md" 101 | 102 | copyright: | 103 | © 2024 Gaoxing Li 104 | -------------------------------------------------------------------------------- /okec-config.cmake.in: -------------------------------------------------------------------------------- 1 | @PACKAGE_INIT@ 2 | 3 | set_and_check(OKEC_LIB_DIR "@PACKAGE_LIB_INSTALL_DIR@") 4 | include("${OKEC_LIB_DIR}/cmake/okec-targets.cmake") 5 | 6 | check_required_components(okec) -------------------------------------------------------------------------------- /src/common/awaitable.cc: -------------------------------------------------------------------------------- 1 | /////////////////////////////////////////////////////////////////////////////// 2 | // __ __ _ ____ ___ 3 | // / \( / )( __)/ __) OKEC(a.k.a. EdgeSim++) 4 | // ( O )) ( ) _)( (__ version 1.0.1 5 | // \__/(__\_)(____)\___) https://github.com/dxnu/okec 6 | // 7 | // Copyright (C) 2023-2024 Gaoxing Li 8 | // Licenced under Apache-2.0 license. See LICENSE.txt for details. 9 | /////////////////////////////////////////////////////////////////////////////// 10 | 11 | #include 12 | #include 13 | #include 14 | #include // exchange 15 | #include 16 | 17 | 18 | namespace okec { 19 | 20 | auto awaitable_promise_base::initial_suspend() noexcept -> std::suspend_never 21 | { 22 | return {}; 23 | } 24 | 25 | auto awaitable_promise_base::final_suspend() noexcept -> std::suspend_always 26 | { 27 | return {}; 28 | } 29 | 30 | auto awaitable_promise_base::unhandled_exception() -> void 31 | { 32 | std::exception_ptr eptr = std::current_exception(); 33 | if (eptr) { 34 | try { 35 | std::rethrow_exception(eptr); 36 | } catch (const std::exception& e) { 37 | log::error("Fatal error: {}", e.what()); 38 | } 39 | } 40 | } 41 | 42 | auto awaitable_promise_base::return_void() -> void 43 | { 44 | } 45 | 46 | awaitable::awaitable(awaitable &&other) noexcept 47 | : handle_{ std::exchange(other.handle_, nullptr) } 48 | { 49 | } 50 | 51 | awaitable &awaitable::operator=(awaitable&& other) noexcept 52 | { 53 | if (handle_) handle_.destroy(); 54 | 55 | handle_ = std::exchange(other.handle_, nullptr); 56 | return *this; 57 | } 58 | 59 | awaitable::~awaitable() 60 | { 61 | if (handle_) { 62 | // std::cout << "awaitable is about to be destroyed\n"; 63 | handle_.destroy(); 64 | } 65 | } 66 | 67 | void awaitable::resume() 68 | { 69 | if (handle_ && !handle_.done()) 70 | handle_.resume(); 71 | } 72 | 73 | // void awaitable::start() 74 | // { 75 | // resume(); 76 | // } 77 | 78 | awaitable::awaitable(std::coroutine_handle handle) noexcept 79 | : handle_{handle} 80 | { 81 | } 82 | 83 | response_awaiter::response_awaiter(simulator& sim, std::string client_address) 84 | : sim{ sim }, 85 | client_address{ client_address } 86 | { 87 | } 88 | 89 | auto response_awaiter::await_ready() noexcept -> bool 90 | { 91 | // log::debug("response_awaiter::await_ready()"); 92 | return false; 93 | } 94 | 95 | auto response_awaiter::await_suspend(std::coroutine_handle<> handle) noexcept -> void 96 | { 97 | // log::debug("response_awaiter::await_suspend()"); 98 | sim.submit(client_address, [this, handle](response&& resp) { 99 | this->r = std::move(resp); 100 | handle.resume(); 101 | }); 102 | } 103 | 104 | auto response_awaiter::await_resume() noexcept -> response 105 | { 106 | // log::debug("response_awaiter::await_resume()"); 107 | return this->r; 108 | } 109 | 110 | auto co_spawn(okec::simulator &ctx, okec::awaitable a) -> void 111 | { 112 | ctx.hold_coro(std::move(a)); 113 | } 114 | 115 | } // namespace okec -------------------------------------------------------------------------------- /src/common/message.cc: -------------------------------------------------------------------------------- 1 | /////////////////////////////////////////////////////////////////////////////// 2 | // __ __ _ ____ ___ 3 | // / \( / )( __)/ __) OKEC(a.k.a. EdgeSim++) 4 | // ( O )) ( ) _)( (__ version 1.0.1 5 | // \__/(__\_)(____)\___) https://github.com/dxnu/okec 6 | // 7 | // Copyright (C) 2023-2024 Gaoxing Li 8 | // Licenced under Apache-2.0 license. See LICENSE.txt for details. 9 | /////////////////////////////////////////////////////////////////////////////// 10 | 11 | #include 12 | 13 | namespace okec 14 | { 15 | 16 | message::message(ns3::Ptr packet) 17 | { 18 | auto j = packet_helper::to_json(packet); 19 | if (!j.is_null()) 20 | j_ = std::move(j); 21 | } 22 | 23 | message::message(std::initializer_list> values) 24 | { 25 | for (auto [key, value] : values) { 26 | j_[key] = value; 27 | } 28 | } 29 | 30 | message::message(const message& other) 31 | : j_ { other.j_ } 32 | { 33 | } 34 | 35 | message& message::operator=(message other) noexcept 36 | { 37 | swap(*this, other); 38 | return *this; 39 | } 40 | 41 | auto message::attribute(std::string_view key, std::string_view value) -> void 42 | { 43 | j_[key] = value; 44 | } 45 | 46 | auto message::get_value(std::string_view key) -> std::string 47 | { 48 | std::string result{}; 49 | if (j_.contains(key)) 50 | result = j_[key].get(); 51 | 52 | return result; 53 | } 54 | 55 | auto message::dump() -> std::string 56 | { 57 | return j_.dump(); 58 | } 59 | 60 | auto message::type(std::string_view sv) -> void { 61 | j_["msgtype"] = sv; 62 | } 63 | 64 | auto message::type() -> std::string 65 | { 66 | return j_["msgtype"]; 67 | } 68 | 69 | // auto message::to_response() -> Ptr 70 | // { 71 | // Ptr r = ns3::Create(); 72 | // if (!j_.is_null()) { 73 | // r->task_id(j_["content"]["response"]["task_id"].get()); 74 | // r->handling_device(j_["content"]["response"]["device_type"].get(), 75 | // j_["content"]["response"]["device_address"].get()); 76 | // r->group(j_["content"]["response"]["group"].get()); 77 | // } 78 | 79 | // return r; 80 | // } 81 | 82 | auto message::to_packet() -> ns3::Ptr 83 | { 84 | return packet_helper::make_packet(this->dump()); 85 | } 86 | 87 | auto message::from_packet(ns3::Ptr packet) -> message 88 | { 89 | return message(packet); 90 | } 91 | 92 | auto message::content(const task& t) -> void { 93 | j_["content"] = t.j_data(); 94 | } 95 | 96 | auto message::content(const task_element& item) -> void 97 | { 98 | j_["content"] = item.j_data(); 99 | } 100 | 101 | auto message::content(const resource& r) -> void 102 | { 103 | j_["content"] = r.j_data(); 104 | } 105 | 106 | auto message::get_task_element() -> task_element 107 | { 108 | if (!j_.is_null() && j_.contains("/content/header"_json_pointer)) 109 | return task_element(j_["content"]); 110 | 111 | return task_element{nullptr}; 112 | } 113 | 114 | auto message::valid() -> bool 115 | { 116 | if (j_.contains("msgtype") && j_.contains("content")) 117 | return true; 118 | else 119 | return false; 120 | } 121 | 122 | void swap(message& lhs, message& rhs) noexcept 123 | { 124 | using std::swap; 125 | swap(lhs.j_, rhs.j_); 126 | } 127 | 128 | } // namespace okec -------------------------------------------------------------------------------- /src/common/resource.cc: -------------------------------------------------------------------------------- 1 | /////////////////////////////////////////////////////////////////////////////// 2 | // __ __ _ ____ ___ 3 | // / \( / )( __)/ __) OKEC(a.k.a. EdgeSim++) 4 | // ( O )) ( ) _)( (__ version 1.0.1 5 | // \__/(__\_)(____)\___) https://github.com/dxnu/okec 6 | // 7 | // Copyright (C) 2023-2024 Gaoxing Li 8 | // Licenced under Apache-2.0 license. See LICENSE.txt for details. 9 | /////////////////////////////////////////////////////////////////////////////// 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | 17 | #define CHECK_INDEX(index) \ 18 | if (index > size()) throw std::out_of_range{"index out of range"} 19 | 20 | 21 | namespace okec 22 | { 23 | 24 | NS_OBJECT_ENSURE_REGISTERED(resource); 25 | 26 | 27 | auto resource::GetTypeId() -> ns3::TypeId 28 | { 29 | static ns3::TypeId tid = ns3::TypeId("okec::resource") 30 | .SetParent(Object::GetTypeId()) 31 | .AddConstructor(); 32 | return tid; 33 | } 34 | 35 | auto resource::install(ns3::Ptr node) -> void 36 | { 37 | node->AggregateObject(this); 38 | node_ = node; 39 | } 40 | 41 | resource::resource(json item) noexcept 42 | { 43 | if (item.contains("/resource"_json_pointer)) { 44 | j_ = std::move(item); 45 | } 46 | } 47 | 48 | auto resource::attribute(std::string_view key, std::string_view value) -> void 49 | { 50 | j_["resource"][key] = value; 51 | } 52 | 53 | auto resource::reset_value(std::string_view key, std::string_view value) -> std::string 54 | { 55 | auto old_value = std::exchange(j_["resource"][key], value); 56 | if (monitor_) { 57 | monitor_(okec::format("{:ip}", get_address()), key, old_value.get(), value); 58 | } 59 | 60 | return old_value; 61 | } 62 | 63 | auto resource::set_monitor(monitor_type monitor) -> void 64 | { 65 | monitor_ = monitor; 66 | } 67 | 68 | auto resource::get_value(std::string_view key) const -> std::string 69 | { 70 | std::string result{}; 71 | json::json_pointer j_key{ "/resource/" + std::string(key) }; 72 | if (j_.contains(j_key)) 73 | j_.at(j_key).get_to(result); 74 | 75 | return result; 76 | } 77 | 78 | auto resource::get_address() -> ns3::Ipv4Address 79 | { 80 | auto ipv4 = node_->GetObject(); 81 | return ipv4->GetAddress(1, 0).GetLocal(); 82 | } 83 | 84 | auto resource::dump(const int indent) -> std::string 85 | { 86 | return j_.dump(indent); 87 | } 88 | 89 | auto resource::empty() const -> bool 90 | { 91 | return !j_.contains("/resource"_json_pointer); 92 | } 93 | 94 | auto resource::j_data() const -> json 95 | { 96 | return j_; 97 | } 98 | 99 | auto resource::set_data(json item) -> bool 100 | { 101 | if (item.contains("/resource"_json_pointer)) { 102 | j_ = std::move(item); 103 | return true; 104 | } 105 | 106 | return false; 107 | } 108 | 109 | auto resource::from_msg_packet(ns3::Ptr packet) -> resource 110 | { 111 | json j = packet_helper::to_json(packet); 112 | if (!j.is_null() && j.contains("/content/resource"_json_pointer)) 113 | return resource(j["content"]); 114 | 115 | return resource{}; 116 | } 117 | 118 | auto make_resource() -> ns3::Ptr 119 | { 120 | return ns3::CreateObject(); 121 | } 122 | 123 | resource_container::resource_container(std::size_t n) 124 | { 125 | m_resources.reserve(n); 126 | for (std::size_t i = 0; i < n; ++i) 127 | m_resources.emplace_back(make_resource()); 128 | } 129 | 130 | auto resource_container::operator[](std::size_t index) -> ns3::Ptr 131 | { 132 | return get(index); 133 | } 134 | 135 | auto resource_container::operator()(std::size_t index) -> ns3::Ptr 136 | { 137 | return get(index); 138 | } 139 | 140 | auto resource_container::get(std::size_t index) -> ns3::Ptr 141 | { 142 | CHECK_INDEX(index); 143 | return m_resources[index]; 144 | } 145 | 146 | auto resource_container::initialize(std::function)> fn) -> void 147 | { 148 | for (auto& item : m_resources) { 149 | fn(item); 150 | } 151 | } 152 | 153 | std::size_t resource_container::size() const 154 | { 155 | return m_resources.size(); 156 | } 157 | 158 | auto resource_container::print(std::string title) -> void 159 | { 160 | // okec::print("{0:=^{1}}\n", title, 150); 161 | 162 | // int index = 1; 163 | // for (const auto& item : m_resources) 164 | // { 165 | // okec::print("[{:>3}] ", index++); 166 | // for (auto it = item->begin(); it != item->end(); ++it) 167 | // { 168 | // okec::print("{}: {} ", it.key(), it.value()); 169 | // } 170 | 171 | // okec::print("\n"); 172 | // } 173 | 174 | // okec::print("{0:=^{1}}\n", "", 150); 175 | } 176 | 177 | auto resource_container::trace_resource() -> void 178 | { 179 | namespace fs = std::filesystem; 180 | static std::ofstream file; 181 | fs::path p{"data/"}; 182 | if (!fs::exists(p)) { 183 | fs::create_directory(p); 184 | } 185 | 186 | p.append("resource_tracer.csv"); 187 | 188 | if (!file.is_open()) { 189 | file.open(p, std::ios::out/* | std::ios::app*/); 190 | if (!file.is_open()) { 191 | return; 192 | } 193 | } 194 | 195 | // for (const auto& item : m_resources) { 196 | // file << okec::format("At time {:.2f}s,{:ip}", Simulator::Now().GetSeconds(), item->get_address()); 197 | // for (auto it = item->begin(); it != item->end(); ++it) { 198 | // file << okec::format(",{}: {}", it.key(), it.value()); 199 | // } 200 | // file << "\n"; 201 | // } 202 | // file << "\n"; 203 | file << okec::format("{:.2f}", ns3::Simulator::Now().GetSeconds()); 204 | for (const auto& item : m_resources) { 205 | for (auto it = item->begin(); it != item->end(); ++it) { 206 | file << okec::format(",{}", it.value().get()); 207 | } 208 | } 209 | file << "\n"; 210 | } 211 | 212 | auto resource_container::save_to_file(const std::string& file) -> void 213 | { 214 | json data; 215 | for (const auto& item : m_resources) { 216 | data["resource"]["items"].emplace_back(item->j_data()); 217 | } 218 | 219 | std::ofstream fout(file); 220 | fout << std::setw(4) << data << std::endl; 221 | } 222 | 223 | auto resource_container::load_from_file(const std::string& file) -> bool 224 | { 225 | std::ifstream fin(file); 226 | if (!fin.is_open()) 227 | return false; 228 | 229 | json data; 230 | fin >> data; 231 | 232 | 233 | if (!data.contains("/resource/items"_json_pointer) || data["resource"]["items"].size() != this->size()) 234 | return false; 235 | 236 | 237 | okec::print("Items: \n"); 238 | auto&& items = data["resource"]["items"]; 239 | for (auto i = 0uz; i < size(); ++i) { 240 | okec::print("{}\n", items[i].dump(4)); 241 | m_resources[i]->set_data(std::move(items[i])); 242 | } 243 | 244 | return true; 245 | } 246 | 247 | auto resource_container::set_monitor(resource::monitor_type monitor) -> void 248 | { 249 | for (const auto& item : m_resources) { 250 | item->set_monitor(monitor); 251 | } 252 | } 253 | 254 | } // namespace okec -------------------------------------------------------------------------------- /src/common/response.cc: -------------------------------------------------------------------------------- 1 | /////////////////////////////////////////////////////////////////////////////// 2 | // __ __ _ ____ ___ 3 | // / \( / )( __)/ __) OKEC(a.k.a. EdgeSim++) 4 | // ( O )) ( ) _)( (__ version 1.0.1 5 | // \__/(__\_)(____)\___) https://github.com/dxnu/okec 6 | // 7 | // Copyright (C) 2023-2024 Gaoxing Li 8 | // Licenced under Apache-2.0 license. See LICENSE.txt for details. 9 | /////////////////////////////////////////////////////////////////////////////// 10 | 11 | #include 12 | #include 13 | 14 | namespace okec 15 | { 16 | 17 | response::response(const response& other) noexcept 18 | { 19 | if (this != &other) { 20 | this->j_ = other.j_; 21 | } 22 | } 23 | 24 | response& response::operator=(const response& other) noexcept 25 | { 26 | if (this != &other) { 27 | this->j_ = other.j_; 28 | } 29 | 30 | return *this; 31 | } 32 | 33 | response::response(response&& other) noexcept 34 | : j_{ std::move(other.j_) } 35 | { 36 | } 37 | 38 | response& response::operator=(response&& other) noexcept 39 | { 40 | j_ = std::move(other.j_); 41 | return *this; 42 | } 43 | 44 | auto response::begin() -> iterator 45 | { 46 | return this->view().begin(); 47 | } 48 | 49 | auto response::end() -> iterator 50 | { 51 | return this->view().end(); 52 | } 53 | 54 | auto response::dump(int indent) -> std::string 55 | { 56 | return j_.dump(indent); 57 | } 58 | 59 | auto response::view() -> value_type& 60 | { 61 | return j_["response"]["items"]; 62 | } 63 | 64 | auto response::size() const -> std::size_t 65 | { 66 | return data().size(); 67 | } 68 | 69 | auto response::emplace_back(attributes_type values) -> void 70 | { 71 | json item; 72 | for (auto [key, value] : values) { 73 | item[key] = value; 74 | } 75 | 76 | // j_["response"]["items"].emplace_back(std::move(item)); 77 | this->emplace_back(std::move(item)); 78 | } 79 | 80 | auto response::find_if(unary_predicate_type pred) -> iterator 81 | { 82 | auto& items = this->view(); 83 | return std::find_if(items.begin(), items.end(), pred); 84 | } 85 | 86 | auto response::count_if(unary_predicate_type pred) const -> int 87 | { 88 | const auto& items = j_["response"]["items"]; 89 | return std::count_if(items.begin(), items.end(), pred); 90 | } 91 | 92 | auto response::dump_with(unary_predicate_type pred) -> response 93 | { 94 | response result; 95 | auto& items = this->view(); 96 | for (auto it = items.begin(); it != items.end();) { 97 | if (pred(*it)) { 98 | result.emplace_back(std::move(*it)); 99 | it = items.erase(it); 100 | } else { 101 | it++; 102 | } 103 | } 104 | return result; 105 | } 106 | 107 | auto response::dump_with(attributes_type values) -> response 108 | { 109 | response res; 110 | auto& items = j_["response"]["items"]; 111 | for (std::size_t i = 0; i < items.size(); ++i) 112 | { 113 | bool cond = true; 114 | for (auto [key, value] : values) 115 | { 116 | if (items[i][key] != value) { 117 | cond = false; 118 | break; 119 | } 120 | } 121 | 122 | if (cond) 123 | { 124 | res.emplace_back(std::move(items[i])); 125 | } 126 | } 127 | 128 | // 清除移出的元素 129 | for (auto iter = items.begin(); iter != items.end();) 130 | { 131 | if (iter->is_null()) 132 | iter = items.erase(iter); 133 | else 134 | iter++; 135 | } 136 | 137 | return res; 138 | } 139 | 140 | auto response::dump_with(attribute_type value) -> response 141 | { 142 | return dump_with({value}); 143 | } 144 | 145 | auto response::emplace_back(json item) -> void 146 | { 147 | j_["response"]["items"].emplace_back(std::move(item)); 148 | } 149 | 150 | } // namespace okec -------------------------------------------------------------------------------- /src/common/simulator.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | 7 | 8 | namespace okec 9 | { 10 | 11 | simulator::simulator(ns3::Time time) 12 | : stop_time_{std::move(time)} 13 | { 14 | // log::debug("C++ version: {}", __cplusplus); 15 | ns3::Time::SetResolution(ns3::Time::NS); 16 | } 17 | 18 | simulator::~simulator() 19 | { 20 | ns3::Simulator::Destroy(); 21 | } 22 | 23 | auto simulator::run() -> void 24 | { 25 | ns3::Simulator::Stop(stop_time_); 26 | ns3::Simulator::Run(); 27 | } 28 | 29 | auto simulator::stop_time(ns3::Time time) -> void 30 | { 31 | stop_time_ = std::move(time); 32 | } 33 | 34 | auto simulator::stop_time() const -> ns3::Time 35 | { 36 | return stop_time_; 37 | } 38 | 39 | auto simulator::enable_visualizer() -> void 40 | { 41 | ns3::GlobalValue::Bind("SimulatorImplementationType", ns3::StringValue("ns3::VisualSimulatorImpl")); 42 | } 43 | 44 | auto simulator::submit(const std::string &ip, std::function fn) -> void 45 | { 46 | completion_[ip] = fn; 47 | } 48 | 49 | auto simulator::complete(const std::string& ip, response&& r) -> void 50 | { 51 | if (auto it = completion_.find(ip); 52 | it != completion_.end()) { 53 | auto fn = it->second; 54 | completion_.erase(it); 55 | fn(std::move(r)); 56 | } 57 | } 58 | 59 | auto simulator::is_valid(const std::string &ip) -> bool 60 | { 61 | if (auto it = completion_.find(ip); 62 | it != completion_.end()) { 63 | return true; 64 | } 65 | 66 | return false; 67 | } 68 | 69 | auto simulator::hold_coro(awaitable a) -> void 70 | { 71 | coros_.emplace_back(std::move(a)); 72 | // coros_[coros_.size() - 1].start(); 73 | } 74 | 75 | 76 | } // namespace okec -------------------------------------------------------------------------------- /src/devices/client_device.cc: -------------------------------------------------------------------------------- 1 | /////////////////////////////////////////////////////////////////////////////// 2 | // __ __ _ ____ ___ 3 | // / \( / )( __)/ __) OKEC(a.k.a. EdgeSim++) 4 | // ( O )) ( ) _)( (__ version 1.0.1 5 | // \__/(__\_)(____)\___) https://github.com/dxnu/okec 6 | // 7 | // Copyright (C) 2023-2024 Gaoxing Li 8 | // Licenced under Apache-2.0 license. See LICENSE.txt for details. 9 | /////////////////////////////////////////////////////////////////////////////// 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | 21 | 22 | namespace okec 23 | { 24 | 25 | client_device::client_device(simulator& sim) 26 | : sim_{ sim }, 27 | m_node{ ns3::CreateObject() }, 28 | m_udp_application{ ns3::CreateObject() } 29 | { 30 | m_udp_application->SetStartTime(ns3::Seconds(0)); 31 | m_udp_application->SetStopTime(sim_.stop_time()); 32 | 33 | // 为当前设备安装通信功能 34 | m_node->AddApplication(m_udp_application); 35 | } 36 | 37 | auto client_device::get_resource() -> ns3::Ptr 38 | { 39 | return m_node->GetObject(); 40 | } 41 | 42 | auto client_device::get_address() const -> ns3::Ipv4Address 43 | { 44 | auto ipv4 = m_node->GetObject(); 45 | return ipv4->GetAddress(1, 0).GetLocal(); 46 | } 47 | 48 | auto client_device::get_port() const -> uint16_t 49 | { 50 | return m_udp_application->get_port(); 51 | } 52 | 53 | auto client_device::get_node() -> ns3::Ptr 54 | { 55 | return m_node; 56 | } 57 | 58 | auto client_device::install_resource(ns3::Ptr res) -> void 59 | { 60 | res->install(m_node); 61 | } 62 | 63 | auto client_device::send(task t) -> void 64 | { 65 | // 任务不能以 task 为单位发送,因为 task 可能会非常大,导致发送的数据断页,在目的端便无法恢复数据 66 | // 以 task_element 为单位发送则可以避免 task 大小可能会带来的问题 67 | // double launch_delay{ 1.0 }; 68 | for (auto&& item : t.elements_view()) { 69 | m_decision_engine->send(std::move(item), shared_from_this()); 70 | } 71 | } 72 | 73 | auto client_device::async_send(task t) -> std::suspend_never 74 | { 75 | for (auto&& item : t.elements_view()) { 76 | m_decision_engine->send(std::move(item), shared_from_this()); 77 | } 78 | 79 | return {}; 80 | } 81 | 82 | auto client_device::async_read() -> response_awaiter 83 | { 84 | return response_awaiter{sim_, okec::format("{:ip}", this->get_address())}; 85 | } 86 | 87 | auto client_device::async_read(done_callback_t fn) -> void 88 | { 89 | m_done_fn = fn; 90 | } 91 | 92 | auto client_device::when_done(response_type resp) -> void 93 | { 94 | auto ip = okec::format("{:ip}", this->get_address()); 95 | if (sim_.is_valid(ip)) { 96 | sim_.complete(ip, std::move(resp)); 97 | } 98 | 99 | if (this->has_done_callback()) { 100 | std::invoke(m_done_fn, std::move(resp)); 101 | } 102 | } 103 | 104 | auto client_device::set_position(double x, double y, double z) -> void 105 | { 106 | ns3::Ptr mobility = m_node->GetObject(); 107 | if (!mobility) { 108 | mobility = ns3::CreateObject(); 109 | mobility->SetPosition(ns3::Vector(x, y, z)); 110 | m_node->AggregateObject(mobility); 111 | } else { 112 | mobility->SetPosition(ns3::Vector(x, y, z)); 113 | } 114 | } 115 | 116 | auto client_device::get_position() -> ns3::Vector 117 | { 118 | ns3::Ptr mobility = m_node->GetObject(); 119 | return mobility ? mobility->GetPosition() : ns3::Vector(-1.0, -1.0, -1.0); 120 | } 121 | 122 | auto client_device::set_decision_engine(std::shared_ptr engine) -> void 123 | { 124 | m_decision_engine = engine; 125 | } 126 | 127 | auto client_device::set_request_handler(std::string_view msg_type, callback_type callback) -> void 128 | { 129 | m_udp_application->set_request_handler(msg_type, 130 | [callback, this](ns3::Ptr packet, const ns3::Address& remote_address) { 131 | callback(this, packet, remote_address); 132 | }); 133 | } 134 | 135 | auto client_device::dispatch(std::string_view msg_type, ns3::Ptr packet, const ns3::Address& address) -> void 136 | { 137 | m_udp_application->dispatch(msg_type, packet, address); 138 | } 139 | 140 | auto client_device::response_cache() -> response_type& 141 | { 142 | return m_response; 143 | } 144 | 145 | auto client_device::has_done_callback() -> bool 146 | { 147 | return m_done_fn ? true : false; 148 | } 149 | 150 | auto client_device::done_callback(response_type res) -> void 151 | { 152 | std::invoke(m_done_fn, std::move(res)); 153 | } 154 | 155 | auto client_device::write(ns3::Ptr packet, ns3::Ipv4Address destination, uint16_t port) const -> void 156 | { 157 | m_udp_application->write(packet, destination, port); 158 | } 159 | 160 | auto client_device_container::operator[](std::size_t index) -> pointer_type 161 | { 162 | return this->get_device(index); 163 | } 164 | 165 | auto client_device_container::operator()(std::size_t index) -> pointer_type 166 | { 167 | return this->get_device(index); 168 | } 169 | 170 | auto client_device_container::get_device(std::size_t index) -> pointer_type 171 | { 172 | return m_devices[index]; 173 | } 174 | 175 | auto client_device_container::size() -> std::size_t 176 | { 177 | return m_devices.size(); 178 | } 179 | 180 | auto client_device_container::install_resources(resource_container& res, int offset) -> void 181 | { 182 | for (std::size_t i = 0; i < this->size(); ++i) { 183 | if (i + offset < res.size()) 184 | m_devices[i]->install_resource(res[i + offset]); 185 | } 186 | } 187 | 188 | auto client_device_container::set_decision_engine(std::shared_ptr engine) -> void 189 | { 190 | for (pointer_type bs : m_devices) { 191 | bs->set_decision_engine(engine); 192 | } 193 | } 194 | 195 | auto client_device_container::set_request_handler(std::string_view msg_type, callback_type callback) 196 | -> void 197 | { 198 | std::ranges::for_each(m_devices, 199 | [&msg_type, callback](pointer_type client) { 200 | client->set_request_handler(msg_type, callback); 201 | }); 202 | } 203 | 204 | } // namespace okec -------------------------------------------------------------------------------- /src/devices/cloud_server.cc: -------------------------------------------------------------------------------- 1 | /////////////////////////////////////////////////////////////////////////////// 2 | // __ __ _ ____ ___ 3 | // / \( / )( __)/ __) OKEC(a.k.a. EdgeSim++) 4 | // ( O )) ( ) _)( (__ version 1.0.1 5 | // \__/(__\_)(____)\___) https://github.com/dxnu/okec 6 | // 7 | // Copyright (C) 2023-2024 Gaoxing Li 8 | // Licenced under Apache-2.0 license. See LICENSE.txt for details. 9 | /////////////////////////////////////////////////////////////////////////////// 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | 19 | namespace okec 20 | { 21 | 22 | cloud_server::cloud_server(simulator& sim) 23 | : sim_{ sim }, 24 | m_node{ ns3::CreateObject() }, 25 | m_udp_application{ ns3::CreateObject() } 26 | { 27 | m_udp_application->SetStartTime(ns3::Seconds(0)); 28 | m_udp_application->SetStopTime(sim_.stop_time()); 29 | 30 | // 为当前设备安装通信功能 31 | m_node->AddApplication(m_udp_application); 32 | 33 | // 设置默认回调函数 34 | m_udp_application->set_request_handler(message_get_resource_information, [this](ns3::Ptr packet, const ns3::Address& remote_address) { 35 | this->on_get_resource_information(packet, remote_address); 36 | }); 37 | } 38 | 39 | auto cloud_server::get_node() -> ns3::Ptr 40 | { 41 | return m_node; 42 | } 43 | 44 | auto cloud_server::get_nodes(ns3::NodeContainer& nodes) -> void 45 | { 46 | nodes.Add(m_node); 47 | } 48 | 49 | auto cloud_server::get_address() const -> ns3::Ipv4Address 50 | { 51 | auto ipv4 = m_node->GetObject(); 52 | return ipv4 ? ipv4->GetAddress(1, 0).GetLocal() : ns3::Ipv4Address{}; 53 | } 54 | 55 | auto cloud_server::get_port() const -> uint16_t 56 | { 57 | return m_udp_application->get_port(); 58 | } 59 | 60 | auto cloud_server::get_resource() -> ns3::Ptr 61 | { 62 | return m_node->GetObject(); 63 | } 64 | 65 | auto cloud_server::install_resource(ns3::Ptr res) -> void 66 | { 67 | res->install(m_node); 68 | } 69 | 70 | auto cloud_server::set_position(double x, double y, double z) -> void 71 | { 72 | ns3::Ptr mobility = m_node->GetObject(); 73 | if (!mobility) { 74 | mobility = ns3::CreateObject(); 75 | mobility->SetPosition(ns3::Vector(x, y, z)); 76 | m_node->AggregateObject(mobility); 77 | } else { 78 | mobility->SetPosition(ns3::Vector(x, y, z)); 79 | } 80 | } 81 | 82 | auto cloud_server::get_position() -> ns3::Vector 83 | { 84 | ns3::Ptr mobility = m_node->GetObject(); 85 | return mobility ? mobility->GetPosition() : ns3::Vector(); 86 | } 87 | 88 | auto cloud_server::set_request_handler(std::string_view msg_type, callback_type callback) -> void 89 | { 90 | m_udp_application->set_request_handler(msg_type, 91 | [callback, this](ns3::Ptr packet, const ns3::Address& remote_address) { 92 | callback(this, packet, remote_address); 93 | }); 94 | } 95 | 96 | auto cloud_server::write(ns3::Ptr packet, ns3::Ipv4Address destination, uint16_t port) const -> void 97 | { 98 | m_udp_application->write(packet, destination, port); 99 | } 100 | 101 | auto cloud_server::on_get_resource_information(ns3::Ptr packet, const ns3::Address& remote_address) -> void 102 | { 103 | auto device_resource = get_resource(); 104 | if (!device_resource || device_resource->empty()) 105 | return; // 没有安装资源,或资源为空,都不返回任何消息 106 | 107 | 108 | message msg { 109 | { "msgtype", "resource_information" }, 110 | { "device_type", "cs" }, 111 | { "pos_x", okec::format("{}", get_position().x) }, 112 | { "pos_y", okec::format("{}", get_position().y) }, 113 | { "pos_z", okec::format("{}", get_position().z) } 114 | }; 115 | msg.content(*device_resource); 116 | m_udp_application->write(msg.to_packet(), ns3::InetSocketAddress::ConvertFrom(remote_address).GetIpv4(), 8860); 117 | } 118 | 119 | 120 | } // namespace okec 121 | -------------------------------------------------------------------------------- /src/devices/edge_device.cc: -------------------------------------------------------------------------------- 1 | /////////////////////////////////////////////////////////////////////////////// 2 | // __ __ _ ____ ___ 3 | // / \( / )( __)/ __) OKEC(a.k.a. EdgeSim++) 4 | // ( O )) ( ) _)( (__ version 1.0.1 5 | // \__/(__\_)(____)\___) https://github.com/dxnu/okec 6 | // 7 | // Copyright (C) 2023-2024 Gaoxing Li 8 | // Licenced under Apache-2.0 license. See LICENSE.txt for details. 9 | /////////////////////////////////////////////////////////////////////////////// 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | 21 | namespace okec 22 | { 23 | 24 | edge_device::edge_device(simulator& sim) 25 | : sim_{ sim }, 26 | m_node{ ns3::CreateObject() }, 27 | m_udp_application{ ns3::CreateObject() } 28 | { 29 | m_udp_application->SetStartTime(ns3::Seconds(0)); 30 | m_udp_application->SetStopTime(sim_.stop_time()); 31 | 32 | // 为当前设备安装通信功能 33 | m_node->AddApplication(m_udp_application); 34 | 35 | // 设置请求回调函数 36 | m_udp_application->set_request_handler("get_resource_information", [this](ns3::Ptr packet, const ns3::Address& remote_address) { 37 | this->on_get_resource_information(packet, remote_address); 38 | }); 39 | } 40 | 41 | auto edge_device::get_address() const -> ns3::Ipv4Address 42 | { 43 | auto ipv4 = m_node->GetObject(); 44 | return ipv4->GetAddress(1, 0).GetLocal(); 45 | } 46 | 47 | auto edge_device::get_port() const -> uint16_t 48 | { 49 | return m_udp_application->get_port(); 50 | } 51 | 52 | auto edge_device::get_node() -> ns3::Ptr 53 | { 54 | return m_node; 55 | } 56 | 57 | auto edge_device::get_resource() -> ns3::Ptr 58 | { 59 | return m_node->GetObject(); 60 | } 61 | 62 | auto edge_device::install_resource(ns3::Ptr res) -> void 63 | { 64 | res->install(m_node); 65 | } 66 | 67 | auto edge_device::set_position(double x, double y, double z) -> void 68 | { 69 | ns3::Ptr mobility = m_node->GetObject(); 70 | if (!mobility) { 71 | mobility = ns3::CreateObject(); 72 | mobility->SetPosition(ns3::Vector(x, y, z)); 73 | m_node->AggregateObject(mobility); 74 | } else { 75 | mobility->SetPosition(ns3::Vector(x, y, z)); 76 | } 77 | } 78 | 79 | auto edge_device::get_position() -> ns3::Vector 80 | { 81 | ns3::Ptr mobility = m_node->GetObject(); 82 | return mobility ? mobility->GetPosition() : ns3::Vector(); 83 | } 84 | 85 | auto edge_device::set_request_handler(std::string_view msg_type, callback_type callback) -> void 86 | { 87 | m_udp_application->set_request_handler(msg_type, 88 | [callback, this](ns3::Ptr packet, const ns3::Address& remote_address) { 89 | callback(this, packet, remote_address); 90 | }); 91 | } 92 | 93 | auto edge_device::write(ns3::Ptr packet, ns3::Ipv4Address destination, uint16_t port) const -> void 94 | { 95 | m_udp_application->write(packet, destination, port); 96 | } 97 | 98 | auto edge_device::on_get_resource_information(ns3::Ptr packet, const ns3::Address& remote_address) -> void 99 | { 100 | // okec::print("on_get_resource_information from {:ip}\n", InetSocketAddress::ConvertFrom(remote_address).GetIpv4()); 101 | auto device_resource = get_resource(); 102 | if (!device_resource || device_resource->empty()) 103 | return; // 没有安装资源,或资源为空,都不返回任何消息 104 | 105 | 106 | message msg { 107 | { "msgtype", message_resource_information }, 108 | { "device_type", "es" }, 109 | { "ip", okec::format("{:ip}", this->get_address()) }, 110 | { "port", okec::format("{}", this->get_port()) }, 111 | { "pos_x", okec::format("{}", get_position().x) }, 112 | { "pos_y", okec::format("{}", get_position().y) }, 113 | { "pos_z", okec::format("{}", get_position().z) } 114 | }; 115 | msg.content(*device_resource); 116 | this->write(msg.to_packet(), ns3::InetSocketAddress::ConvertFrom(remote_address).GetIpv4(), 8860); 117 | } 118 | 119 | edge_device_container::edge_device_container(simulator& sim, std::size_t n) 120 | { 121 | m_devices.reserve(n); 122 | for (std::size_t i = 0; i < n; ++i) 123 | m_devices.emplace_back(std::make_shared(sim)); 124 | } 125 | 126 | auto edge_device_container::get_nodes(ns3::NodeContainer& nodes) -> void 127 | { 128 | for (auto& device : m_devices) 129 | nodes.Add(device->get_node()); 130 | } 131 | 132 | auto edge_device_container::get_device(std::size_t index) -> pointer_type 133 | { 134 | return m_devices[index]; 135 | } 136 | 137 | auto edge_device_container::size() -> std::size_t 138 | { 139 | return m_devices.size(); 140 | } 141 | 142 | auto edge_device_container::install_resources(resource_container& res, int offset) -> void 143 | { 144 | for (std::size_t i = 0; i < this->size(); ++i) { 145 | if (i + offset < res.size()) 146 | m_devices[i]->install_resource(res[i + offset]); 147 | } 148 | } 149 | 150 | 151 | } // namespace okec -------------------------------------------------------------------------------- /src/network/udp_application.cc: -------------------------------------------------------------------------------- 1 | /////////////////////////////////////////////////////////////////////////////// 2 | // __ __ _ ____ ___ 3 | // / \( / )( __)/ __) OKEC(a.k.a. EdgeSim++) 4 | // ( O )) ( ) _)( (__ version 1.0.1 5 | // \__/(__\_)(____)\___) https://github.com/dxnu/okec 6 | // 7 | // Copyright (C) 2023-2024 Gaoxing Li 8 | // Licenced under Apache-2.0 license. See LICENSE.txt for details. 9 | /////////////////////////////////////////////////////////////////////////////// 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | // #define PURPLE_CODE "\033[95m" 26 | // #define CYAN_CODE "\033[96m" 27 | // #define TEAL_CODE "\033[36m" 28 | // #define BLUE_CODE "\033[94m" 29 | // #define GREEN_CODE "\033[32m" 30 | // #define YELLOW_CODE "\033[33m" 31 | // #define LIGHT_YELLOW_CODE "\033[93m" 32 | // #define RED_CODE "\033[91m" 33 | // #define BOLD_CODE "\033[1m" 34 | // #define END_CODE "\033[0m" 35 | 36 | 37 | namespace okec 38 | { 39 | 40 | // NS_LOG_COMPONENT_DEFINE("udp_application"); 41 | // NS_OBJECT_ENSURE_REGISTERED(udp_application); 42 | 43 | 44 | udp_application::udp_application() 45 | : m_port{ 8860 }, 46 | m_recv_socket{ nullptr }, 47 | m_send_socket{ nullptr } 48 | { 49 | } 50 | 51 | udp_application::~udp_application() 52 | { 53 | } 54 | 55 | auto udp_application::GetTypeId() -> ns3::TypeId 56 | { 57 | static ns3::TypeId tid = ns3::TypeId("okec::udp_application") 58 | .AddConstructor() 59 | .SetParent(); 60 | return tid; 61 | } 62 | 63 | auto udp_application::GetInstanceTypeId() const -> ns3::TypeId 64 | { 65 | return udp_application::GetTypeId(); 66 | } 67 | 68 | auto udp_application::read_handler(ns3::Ptr socket) -> void 69 | { 70 | // NS_LOG_FUNCTION(this << socket); 71 | ns3::Ptr packet; 72 | ns3::Address remote_address; 73 | 74 | while ((packet = socket->RecvFrom(remote_address))) { 75 | auto content = packet_helper::to_string(packet); 76 | log::debug("{:ip} has received a packet: \"{}\" size: {}", this->get_address(), content, content.size()); 77 | if (packet) { 78 | auto msg_type = get_message_type(packet); 79 | log::debug("{:ip} is processing [{}] message...", this->get_address(), msg_type); 80 | auto dispatched = m_msg_handler.dispatch(msg_type, packet, remote_address); 81 | NS_ASSERT_MSG(dispatched, "Invalid message type: " << msg_type); 82 | } 83 | } 84 | } 85 | 86 | auto udp_application::write(ns3::Ptr packet, ns3::Ipv4Address destination, uint16_t port) -> void 87 | { 88 | log::debug("{:ip}:{} ---> {:ip}:{}", this->get_address(), this->get_port(), ns3::Ipv4Address::ConvertFrom(destination), port); 89 | // NS_LOG_FUNCTION (this << packet << destination << port); 90 | 91 | m_send_socket->Connect(ns3::InetSocketAddress(destination, port)); 92 | m_send_socket->Send(packet); 93 | } 94 | 95 | auto udp_application::get_address() -> ns3::Ipv4Address const 96 | { 97 | return get_socket_address(m_recv_socket); 98 | } 99 | 100 | auto udp_application::get_port() -> u_int16_t const 101 | { 102 | return m_port; 103 | } 104 | 105 | auto udp_application::set_request_handler(std::string_view msg_type, callback_type callback) -> void 106 | { 107 | m_msg_handler.add_handler(msg_type, callback); 108 | } 109 | 110 | auto udp_application::dispatch(std::string_view msg_type, ns3::Ptr packet, const ns3::Address& address) -> void 111 | { 112 | m_msg_handler.dispatch(msg_type.data(), packet, address); 113 | } 114 | 115 | auto udp_application::StartApplication() -> void 116 | { 117 | ns3::TypeId tid = ns3::TypeId::LookupByName("ns3::UdpSocketFactory"); 118 | m_recv_socket = ns3::Socket::CreateSocket(GetNode(), tid); 119 | 120 | ns3::InetSocketAddress local = ns3::InetSocketAddress(ns3::Ipv4Address::GetAny(), m_port); 121 | if (m_recv_socket->Bind(local) == -1) { 122 | log::error("Failed to build socket"); 123 | return; 124 | } 125 | 126 | m_recv_socket->SetRecvCallback(MakeCallback(&udp_application::read_handler, this)); 127 | 128 | m_send_socket = ns3::Socket::CreateSocket(GetNode(), tid); 129 | } 130 | 131 | auto udp_application::StopApplication() -> void 132 | { 133 | m_recv_socket->Close(); 134 | m_send_socket->Close(); 135 | } 136 | 137 | auto udp_application::get_socket_address(ns3::Ptr socket) -> ns3::Ipv4Address 138 | { 139 | // 获取当前IP地址 140 | ns3::Ptr ipv4 = socket->GetNode()->GetObject(); 141 | return ipv4->GetAddress(1, 0).GetLocal(); 142 | } 143 | 144 | 145 | } // namespace simeg -------------------------------------------------------------------------------- /src/utils/packet_helper.cc: -------------------------------------------------------------------------------- 1 | /////////////////////////////////////////////////////////////////////////////// 2 | // __ __ _ ____ ___ 3 | // / \( / )( __)/ __) OKEC(a.k.a. EdgeSim++) 4 | // ( O )) ( ) _)( (__ version 1.0.1 5 | // \__/(__\_)(____)\___) https://github.com/dxnu/okec 6 | // 7 | // Copyright (C) 2023-2024 Gaoxing Li 8 | // Licenced under Apache-2.0 license. See LICENSE.txt for details. 9 | /////////////////////////////////////////////////////////////////////////////// 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | 16 | namespace okec { 17 | namespace packet_helper { 18 | 19 | 20 | auto make_packet(std::string_view sv) -> ns3::Ptr 21 | { 22 | return ns3::Create((uint8_t*)sv.data(), sv.length() + 1); 23 | } 24 | 25 | auto to_string(ns3::Ptr packet) -> std::string 26 | { 27 | auto size = packet->GetSize(); 28 | auto buffer = new uint8_t[size]; 29 | packet->CopyData(buffer, size); 30 | auto data = std::string(buffer, buffer + size); 31 | delete[] buffer; 32 | 33 | return data; 34 | } 35 | 36 | auto to_json(ns3::Ptr packet) -> json 37 | { 38 | json j; 39 | auto data = to_string(packet); 40 | return j.accept(data) ? j.parse(data) : j; 41 | } 42 | 43 | 44 | } // namespace packet_helper 45 | } // namespace okec -------------------------------------------------------------------------------- /src/utils/read_csv.cc: -------------------------------------------------------------------------------- 1 | /////////////////////////////////////////////////////////////////////////////// 2 | // __ __ _ ____ ___ 3 | // / \( / )( __)/ __) OKEC(a.k.a. EdgeSim++) 4 | // ( O )) ( ) _)( (__ version 1.0.1 5 | // \__/(__\_)(____)\___) https://github.com/dxnu/okec 6 | // 7 | // Copyright (C) 2023-2024 Gaoxing Li 8 | // Licenced under Apache-2.0 license. See LICENSE.txt for details. 9 | /////////////////////////////////////////////////////////////////////////////// 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | 16 | auto okec::read_csv(std::string_view file, std::string_view type, std::string_view delimiter) 17 | -> std::optional 18 | { 19 | std::ifstream data_file(file.data()); 20 | if (!data_file.is_open()) { 21 | return {}; 22 | } 23 | 24 | std::string line; 25 | std::getline(data_file, line); // skip the title 26 | dataset_sequence_type result; 27 | while (std::getline(data_file, line)) { 28 | auto tokens = line 29 | | std::views::split(delimiter) 30 | | std::views::transform([](auto&& token) { 31 | return std::string_view(&*token.begin(), std::ranges::distance(token)); 32 | }); 33 | 34 | auto it = std::ranges::begin(tokens); 35 | std::ranges::advance(it, 2); 36 | if (type.empty() || *it == type) { 37 | // save all records or filtered records. 38 | result.push_back(dataset_sequence_type::value_type(tokens.begin(), tokens.end())); 39 | } 40 | } 41 | 42 | return result; 43 | } -------------------------------------------------------------------------------- /src/utils/sys.cc: -------------------------------------------------------------------------------- 1 | /////////////////////////////////////////////////////////////////////////////// 2 | // __ __ _ ____ ___ 3 | // / \( / )( __)/ __) OKEC(a.k.a. EdgeSim++) 4 | // ( O )) ( ) _)( (__ version 1.0.1 5 | // \__/(__\_)(____)\___) https://github.com/dxnu/okec 6 | // 7 | // Copyright (C) 2023-2024 Gaoxing Li 8 | // Licenced under Apache-2.0 license. See LICENSE.txt for details. 9 | /////////////////////////////////////////////////////////////////////////////// 10 | 11 | #include 12 | #ifdef __linux__ 13 | #include 14 | #include 15 | #elif _WIN32 16 | #include 17 | #else 18 | #endif 19 | 20 | namespace okec 21 | { 22 | 23 | auto get_winsize() -> winsize_t { 24 | #ifdef __linux__ 25 | struct winsize w; 26 | ioctl(STDOUT_FILENO, TIOCGWINSZ, &w); 27 | return winsize_t { .row = w.ws_row, .col = w.ws_col }; 28 | #elif _WIN32 29 | CONSOLE_SCREEN_BUFFER_INFO csbi; 30 | GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi); 31 | int col = csbi.srWindow.Right - csbi.srWindow.Left + 1; 32 | int row = csbi.srWindow.Bottom - csbi.srWindow.Top + 1; 33 | return winsize_t { .row = row, .col = col }; 34 | #else 35 | return winsize_t { .row = 0, .col = 0 }; 36 | #endif // sys 37 | } 38 | 39 | 40 | } // namespace okec --------------------------------------------------------------------------------