├── .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 | 
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 | 
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 | 
4 |
5 |
6 |
OKEC(a.k.a. EdgeSim++)
7 | A Realistic, Versatile, and Easily Customizable Edge Computing Simulator
8 |
9 |
10 | [](https://ci.appveyor.com/project/lkimuk/okec)
11 | [](https://github.com/lkimuk/okec/blob/main/LICENSE)
12 | [](https://app.codacy.com/gh/lkimuk/okec/dashboard?utm_source=gh&utm_medium=referral&utm_content=&utm_campaign=Badge_grade)
13 | 
14 | 
15 | [](http://isitmaintained.com/project/lkimuk/okec "Average time to resolve an issue")
16 | [](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 | 
7 |
8 | ## multiple_aps_clients_model
9 | The model sets up scenarios with multiple base stations serving clients from different network segments.
10 |
11 | 
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 | 
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 | 
--------------------------------------------------------------------------------
/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 | 
96 | 
--------------------------------------------------------------------------------
/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