├── .idea ├── .gitignore ├── PyEdgeSim.iml ├── inspectionProfiles │ └── profiles_settings.xml ├── misc.xml ├── modules.xml └── vcs.xml ├── LICENSE ├── README.md ├── core ├── __init__.py ├── __pycache__ │ └── __init__.cpython-39.pyc ├── decision_module │ ├── __init__.py │ ├── __pycache__ │ │ ├── __init__.cpython-39.pyc │ │ ├── ec_model.cpython-39.pyc │ │ ├── ec_model_without_schedule.cpython-39.pyc │ │ ├── ec_model_without_schedule.cpython-39_冲突文件_16964_20231024000002.pyc │ │ ├── ec_schedul_model.cpython-39.pyc │ │ └── expression.cpython-39.pyc │ ├── ec_model.py │ ├── ec_model_without_schedule.py │ ├── ec_schedul_model.py │ └── expression.py ├── env_module │ ├── __init__.py │ ├── __pycache__ │ │ ├── __init__.cpython-39.pyc │ │ ├── environment.cpython-39.pyc │ │ └── environment.cpython-39_冲突文件_16964_20231020094222.pyc │ └── environment.py ├── orchestrator_module │ ├── __init__.py │ ├── __pycache__ │ │ ├── __init__.cpython-39.pyc │ │ ├── orchestrator.cpython-39.pyc │ │ └── orchestrator.cpython-39_冲突文件_16964_20231024000002.pyc │ └── orchestrator.py ├── scenario_module │ ├── __init__.py │ ├── __pycache__ │ │ ├── __init__.cpython-39.pyc │ │ ├── device.cpython-39.pyc │ │ ├── edge.cpython-39.pyc │ │ ├── link.cpython-39.pyc │ │ ├── node.cpython-39.pyc │ │ ├── offload_link.cpython-39.pyc │ │ ├── scenario.cpython-39.pyc │ │ └── schedule_link.cpython-39.pyc │ ├── device.py │ ├── edge.py │ ├── link.py │ ├── node.py │ ├── offload_link.py │ ├── scenario.py │ └── schedule_link.py ├── simsetting_module │ ├── __init__.py │ ├── __pycache__ │ │ ├── __init__.cpython-39.pyc │ │ ├── simsetting.cpython-39.pyc │ │ ├── simsetting.cpython-39_冲突文件_16964_20231022140805.pyc │ │ └── simsetting.cpython-39_冲突文件_16964_20231024000002.pyc │ ├── json_files │ │ ├── model_setting.json │ │ ├── scenario_setting.json │ │ └── tasks_setting.json │ ├── json_files_1 │ │ ├── model_setting.json │ │ ├── scenario_setting.json │ │ └── tasks_setting.json │ └── simsetting.py └── task_generator_module │ ├── __init__.py │ ├── __pycache__ │ ├── __init__.cpython-39.pyc │ ├── app.cpython-39.pyc │ ├── applications.cpython-39.pyc │ ├── task.cpython-39.pyc │ ├── task_generator.cpython-39.pyc │ └── task_generator.cpython-39_冲突文件_16964_20231024000002.pyc │ ├── app.py │ ├── applications.py │ ├── task.py │ └── task_generator.py └── simulation_examples └── example_1 └── main.py /.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | -------------------------------------------------------------------------------- /.idea/PyEdgeSim.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /.idea/inspectionProfiles/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # PyEdgeSim 2 | A Python-based simulation environment for edge computing decision-making algorithms with edge task scheduling. 3 | 4 | 项目简介: 5 | 6 | ​ 项目目的 7 | 8 | ​ 项目功能 9 | 10 | ​ 项目特点 11 | 12 | ## 目录 13 | 14 | - [安装](#安装) 15 | - [使用说明](#使用说明) 16 | - [功能介绍](#功能介绍) 17 | - [贡献指南](#贡献指南) 18 | - [许可证](#许可证) 19 | 20 | ## 安装 21 | 22 | 1. 克隆此仓库: 23 | 24 | ```bash 25 | git clone http... 26 | ``` 27 | 28 | 29 | 30 | 2. 安装依赖项 31 | 32 | ```bash 33 | pip install -r requirements.txt 34 | ``` 35 | 36 | 37 | 38 | 3. 配置环境变量 39 | 40 | ## 使用说明 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /core/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # @Time : 2023/10/18 23:18 4 | # @Author : zhangqi 5 | # @File : __init__.py.py 6 | # @Software: PyCharm 7 | -------------------------------------------------------------------------------- /core/__pycache__/__init__.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AtticusZhang/PyEdgeSim/683b90ed37f7a4531ea761d5fbe5ba17b1b82a3a/core/__pycache__/__init__.cpython-39.pyc -------------------------------------------------------------------------------- /core/decision_module/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AtticusZhang/PyEdgeSim/683b90ed37f7a4531ea761d5fbe5ba17b1b82a3a/core/decision_module/__init__.py -------------------------------------------------------------------------------- /core/decision_module/__pycache__/__init__.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AtticusZhang/PyEdgeSim/683b90ed37f7a4531ea761d5fbe5ba17b1b82a3a/core/decision_module/__pycache__/__init__.cpython-39.pyc -------------------------------------------------------------------------------- /core/decision_module/__pycache__/ec_model.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AtticusZhang/PyEdgeSim/683b90ed37f7a4531ea761d5fbe5ba17b1b82a3a/core/decision_module/__pycache__/ec_model.cpython-39.pyc -------------------------------------------------------------------------------- /core/decision_module/__pycache__/ec_model_without_schedule.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AtticusZhang/PyEdgeSim/683b90ed37f7a4531ea761d5fbe5ba17b1b82a3a/core/decision_module/__pycache__/ec_model_without_schedule.cpython-39.pyc -------------------------------------------------------------------------------- /core/decision_module/__pycache__/ec_model_without_schedule.cpython-39_冲突文件_16964_20231024000002.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AtticusZhang/PyEdgeSim/683b90ed37f7a4531ea761d5fbe5ba17b1b82a3a/core/decision_module/__pycache__/ec_model_without_schedule.cpython-39_冲突文件_16964_20231024000002.pyc -------------------------------------------------------------------------------- /core/decision_module/__pycache__/ec_schedul_model.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AtticusZhang/PyEdgeSim/683b90ed37f7a4531ea761d5fbe5ba17b1b82a3a/core/decision_module/__pycache__/ec_schedul_model.cpython-39.pyc -------------------------------------------------------------------------------- /core/decision_module/__pycache__/expression.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AtticusZhang/PyEdgeSim/683b90ed37f7a4531ea761d5fbe5ba17b1b82a3a/core/decision_module/__pycache__/expression.cpython-39.pyc -------------------------------------------------------------------------------- /core/decision_module/ec_model.py: -------------------------------------------------------------------------------- 1 | from pyomo.environ import ConcreteModel, Set, Var, Param, Expression, Objective, Constraint 2 | from pyomo.environ import Binary, Reals, minimize, SolverFactory, value 3 | 4 | from core.simsetting_module.simsetting import simSetting 5 | from core.decision_module.expression import upload_time, received_task, send_task_to, received_task_from_other, \ 6 | send_task_to_other, queue_after_process, queue_before_process, time_of_send_task_to, time_of_send_task_to_other, \ 7 | time_of_received_task_from_other, time_of_deploy, cost_of_deploy, time_of_process, \ 8 | c1, c2, c3, c5, c6, c9, c10, c41, c42, c71, c72, c8, obj_rule 9 | 10 | 11 | def total_time_of_edge(model, j): 12 | return sum(model.upload_time[i, j] for i in model.I) \ 13 | + sum(model.time_of_send_task_to_other[j, a] for a in model.A) \ 14 | + sum(model.time_of_received_task_from_other[j, a] for a in model.A) \ 15 | + sum(model.time_of_deploy[j, a] for a in model.A) \ 16 | + sum(model.time_of_process[j, a] for a in model.A) 17 | 18 | 19 | def total_cost_of_edge(model, j): 20 | return sum(model.C_u[j] * model.upload_time[i, j] for i in model.I) \ 21 | + sum(model.C_d[j, k] * model.send_task_to[j, k, a] for a in model.A for k in model.J if k != j) \ 22 | + sum(model.cost_of_deploy[j, a] for a in model.A) \ 23 | + sum(model.C_c[j] * model.time_of_process[j, a] for a in model.A) 24 | 25 | 26 | class ECModel: 27 | def __init__(self): 28 | self.n_device = 0 29 | self.n_edge = 0 30 | self.n_app = 0 31 | 32 | self.delta = 0 33 | self.beta = 0.5 34 | 35 | self.C_u = {} 36 | self.C_d = {} 37 | self.C_a = [] 38 | self.C_c = [] 39 | 40 | self.p = {} 41 | self.L = {} 42 | self.r = {} 43 | self.R = {} 44 | self.s = [] 45 | self.Ha = [] 46 | self.f = [] 47 | self.Hmax = [] 48 | 49 | self.queue_ = {} 50 | self.y_deploy_ = {} 51 | 52 | def set_parameter(self, **kwargs): 53 | self.n_device = kwargs["n_device"] 54 | self.n_edge = kwargs["n_edge"] 55 | self.n_app = kwargs["n_app"] 56 | 57 | self.delta = kwargs["delta"] 58 | self.beta = kwargs["beta"] 59 | 60 | self.C_u = {j: kwargs["C_u"][j] for j in range(self.n_edge)} 61 | self.C_d = {(j, k): kwargs["C_d"][j][k] for j in range(self.n_edge) for k in range(self.n_edge)} 62 | self.C_a = kwargs["C_a"] 63 | self.C_c = kwargs["C_c"] 64 | 65 | ItoAmap = kwargs["ItoAmap"] 66 | for i in range(self.n_device): 67 | for a in range(self.n_app): 68 | if a == ItoAmap[i]: 69 | self.p[(i, a)] = 1 70 | else: 71 | self.p[(i, a)] = 1 72 | 73 | self.L = kwargs["L"] 74 | self.r = kwargs["r"] 75 | self.R = kwargs["R"] 76 | self.s = kwargs["s"] 77 | self.Ha = kwargs["Ha"] 78 | self.f = kwargs["f"] 79 | self.Hmax = kwargs["Hmax"] 80 | 81 | self.queue_ = kwargs["queue_"] 82 | self.y_deploy_ = kwargs["y_deploy_"] 83 | 84 | def create_model(self): 85 | model = ConcreteModel() 86 | 87 | model.I = Set(initialize=range(self.n_device)) 88 | model.J = Set(initialize=range(self.n_edge)) 89 | model.A = Set(initialize=range(self.n_app)) 90 | model.delta = Param(initialize=self.delta) 91 | model.beta = Param(initialize=self.beta) 92 | 93 | model.x = Var(model.I, model.J, within=Binary) 94 | model.y = Var(model.J, model.J, model.A, within=Binary) 95 | model.z = Var(model.J, model.A, within=Binary) 96 | model.theta = Var(model.J, model.J, model.A, within=Reals, bounds=[0,1]) 97 | model.mu = Var(model.J, model.A, within=Reals, bounds=[0,1]) 98 | 99 | model.C_u = Param(model.J, initialize=self.C_u) 100 | model.C_d = Param(model.J, model.J, initialize=self.C_d) 101 | model.C_a = Param(model.A, initialize=self.C_a) 102 | model.C_c = Param(model.J, initialize=self.C_c) 103 | model.p = Param(model.I, model.A, initialize=self.p) 104 | 105 | model.L = Param(model.I, model.A, initialize=self.L) 106 | model.r = Param(model.I, model.J, initialize=self.r) 107 | model.R = Param(model.J, model.J, initialize=self.R) 108 | model.s = Param(model.A, initialize=self.s) 109 | model.Ha = Param(model.A, initialize=self.Ha) 110 | model.f = Param(model.J, initialize=self.f) 111 | model.Hmax = Param(model.J, initialize=self.Hmax) 112 | 113 | model.queue_ = Param(model.J, model.A, initialize=self.queue_) 114 | model.y_deploy_ = Param(model.J, model.A, initialize=self.y_deploy_) 115 | 116 | # 定义表达式 117 | model.upload_time = Expression(model.I, model.J, rule=upload_time) 118 | model.received_task = Expression(model.J, model.A, rule=received_task) 119 | model.send_task_to = Expression(model.J, model.J, model.A, rule=send_task_to) 120 | model.received_task_from_other = Expression(model.J, model.A, rule=received_task_from_other) 121 | model.send_task_to_other = Expression(model.J, model.A, rule=send_task_to_other) 122 | model.queue_before_process = Expression(model.J, model.A, rule=queue_before_process) 123 | model.queue_after_process = Expression(model.J, model.A, rule=queue_after_process) 124 | model.time_of_send_task_to = Expression(model.J, model.J, model.A, rule=time_of_send_task_to) 125 | model.time_of_send_task_to_other = Expression(model.J, model.A, rule=time_of_send_task_to_other) 126 | model.time_of_received_task_from_other = Expression(model.J, model.A, 127 | rule=time_of_received_task_from_other) 128 | model.time_of_deploy = Expression(model.J, model.A, rule=time_of_deploy) 129 | model.cost_of_deploy = Expression(model.J, model.A, rule=cost_of_deploy) 130 | model.time_of_process = Expression(model.J, model.A, rule=time_of_process) 131 | model.total_time_of_edge = Expression(model.J, rule=total_time_of_edge) 132 | model.total_cost_of_edge = Expression(model.J, rule=total_cost_of_edge) 133 | 134 | # 择一约束 135 | model.c1 = Constraint(model.I, rule=c1) 136 | model.c2 = Constraint(model.A, model.J, model.J, rule=c2) 137 | model.c3 = Constraint(model.J, model.A, rule=c3) 138 | model.c41 = Constraint(model.A, model.J, model.J, rule=c41) 139 | model.c42 = Constraint(model.A, model.J, model.J, rule=c42) 140 | model.c5 = Constraint(model.J, model.A, rule=c5) # inf 141 | model.c6 = Constraint(model.A, model.J, model.J, rule=c6) 142 | model.c71 = Constraint(model.A, model.J, rule=c71) 143 | model.c72 = Constraint(model.A, model.J, rule=c72) 144 | # model.c8 = Constraint(model.J, rule=self.c8) 145 | model.c9 = Constraint(model.J, rule=c9) 146 | model.c10 = Constraint(model.J, rule=c10) 147 | 148 | model.obj = Objective(rule=obj_rule, sense=minimize) 149 | 150 | return model 151 | 152 | def solve(self): 153 | model = self.create_model() 154 | opt = SolverFactory('scip') 155 | solution = opt.solve(model) 156 | # 输出求解结果 157 | # solution.write() 158 | 159 | x = { 160 | (i, j): value(model.x[i, j]) 161 | for i in model.I 162 | for j in model.J 163 | } 164 | 165 | y = { 166 | (j, k, a): value(model.y[j, k, a]) 167 | for j in model.J 168 | for k in model.J 169 | for a in model.A 170 | } 171 | 172 | z = { 173 | (j, a): value(model.z[j, a]) 174 | for j in model.J 175 | for a in model.A 176 | } 177 | 178 | theta = { 179 | (j, k, a): value(model.theta[j, k, a]) 180 | for j in model.J 181 | for k in model.J 182 | for a in model.A 183 | } 184 | 185 | mu = { 186 | (j, a): value(model.mu[j, a]) 187 | for j in model.J 188 | for a in model.A 189 | } 190 | 191 | return x, y, z, theta, mu 192 | 193 | 194 | if __name__ == '__main__': 195 | pass 196 | -------------------------------------------------------------------------------- /core/decision_module/ec_model_without_schedule.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # @Time : 2023/10/23 15:59 4 | # @Author : zhangqi 5 | # @File : ec_model_without_schedule.py 6 | # @Software: PyCharm 7 | from pyomo.environ import ConcreteModel, Set, Var, Param, Expression, Objective, Constraint 8 | from pyomo.environ import Binary, Reals, minimize, SolverFactory, value 9 | 10 | from core.simsetting_module.simsetting import simSetting 11 | from core.decision_module.expression import upload_time, received_task, queue_after_process, \ 12 | time_of_deploy, cost_of_deploy, time_of_process, \ 13 | c1, c9, c10, c71, c72, obj_rule 14 | 15 | 16 | def queue_before_process(model, j, a): 17 | return model.queue_[j, a] + model.received_task[j, a] 18 | 19 | 20 | def total_time_of_edge(model, j): 21 | return sum(model.upload_time[i, j] for i in model.I) \ 22 | + sum(model.time_of_deploy[j, a] for a in model.A) \ 23 | + sum(model.time_of_process[j, a] for a in model.A) 24 | 25 | 26 | def total_cost_of_edge(model, j): 27 | return sum(model.C_u[j] * model.upload_time[i, j] for i in model.I) \ 28 | + sum(model.cost_of_deploy[j, a] for a in model.A) \ 29 | + sum(model.C_c[j] * model.time_of_process[j, a] for a in model.A) 30 | 31 | 32 | class ECModel: 33 | def __init__(self): 34 | self.n_device = 0 35 | self.n_edge = 0 36 | self.n_app = 0 37 | 38 | self.delta = 0 39 | self.beta = 0.5 40 | 41 | self.C_u = {} 42 | self.C_d = {} 43 | self.C_a = [] 44 | self.C_c = [] 45 | 46 | self.p = {} 47 | self.L = {} 48 | self.r = {} 49 | self.R = {} 50 | self.s = [] 51 | self.Ha = [] 52 | self.f = [] 53 | self.Hmax = [] 54 | 55 | self.queue_ = {} 56 | self.y_deploy_ = {} 57 | 58 | def set_parameter(self, **kwargs): 59 | self.n_device = kwargs["n_device"] 60 | self.n_edge = kwargs["n_edge"] 61 | self.n_app = kwargs["n_app"] 62 | 63 | self.delta = kwargs["delta"] 64 | self.beta = kwargs["beta"] 65 | 66 | self.C_u = {(j): kwargs["C_u"][j] for j in range(self.n_edge)} 67 | self.C_d = {(j, k): kwargs["C_d"][j][k] for j in range(self.n_edge) for k in range(self.n_edge)} 68 | self.C_a = kwargs["C_a"] 69 | self.C_c = kwargs["C_c"] 70 | 71 | ItoAmap = kwargs["ItoAmap"] 72 | for i in range(self.n_device): 73 | for a in range(self.n_app): 74 | if a == ItoAmap[i]: 75 | self.p[(i, a)] = 1 76 | else: 77 | self.p[(i, a)] = 1 78 | 79 | self.L = kwargs["L"] 80 | self.r = kwargs["r"] 81 | self.R = kwargs["R"] 82 | self.s = kwargs["s"] 83 | self.Ha = kwargs["Ha"] 84 | self.f = kwargs["f"] 85 | self.Hmax = kwargs["Hmax"] 86 | 87 | self.queue_ = kwargs["queue_"] 88 | self.y_deploy_ = kwargs["y_deploy_"] 89 | 90 | def create_model(self): 91 | model = ConcreteModel() 92 | 93 | model.I = Set(initialize=range(self.n_device)) 94 | model.J = Set(initialize=range(self.n_edge)) 95 | model.A = Set(initialize=range(self.n_app)) 96 | model.delta = Param(initialize=self.delta) 97 | model.beta = Param(initialize=self.beta) 98 | 99 | model.x = Var(model.I, model.J, within=Binary) 100 | # model.y = Var(model.J, model.J, model.A, within=Binary) 101 | model.z = Var(model.J, model.A, within=Binary) 102 | # model.theta = Var(model.J, model.J, model.A, within=Reals, bounds=[0, 1]) 103 | model.mu = Var(model.J, model.A, within=Reals, bounds=[0, 1]) 104 | 105 | model.C_u = Param(model.J, initialize=self.C_u) 106 | # model.C_d = Param(model.J, model.J, initialize=self.C_d) 107 | model.C_a = Param(model.A, initialize=self.C_a) 108 | model.C_c = Param(model.J, initialize=self.C_c) 109 | model.p = Param(model.I, model.A, initialize=self.p) 110 | 111 | model.L = Param(model.I, model.A, initialize=self.L) 112 | model.r = Param(model.I, model.J, initialize=self.r) 113 | model.R = Param(model.J, model.J, initialize=self.R) 114 | model.s = Param(model.A, initialize=self.s) 115 | model.Ha = Param(model.A, initialize=self.Ha) 116 | model.f = Param(model.J, initialize=self.f) 117 | model.Hmax = Param(model.J, initialize=self.Hmax) 118 | 119 | model.queue_ = Param(model.J, model.A, initialize=self.queue_) 120 | model.y_deploy_ = Param(model.J, model.A, initialize=self.y_deploy_) 121 | 122 | # 定义表达式 123 | model.upload_time = Expression(model.I, model.J, rule=upload_time) 124 | model.received_task = Expression(model.J, model.A, rule=received_task) 125 | # model.send_task_to = Expression(model.J, model.J, model.A, rule=send_task_to) 126 | # model.received_task_from_other = Expression(model.J, model.A, rule=received_task_from_other) 127 | # model.send_task_to_other = Expression(model.J, model.A, rule=send_task_to_other) 128 | model.queue_before_process = Expression(model.J, model.A, rule=queue_before_process) 129 | model.queue_after_process = Expression(model.J, model.A, rule=queue_after_process) 130 | # model.time_of_send_task_to = Expression(model.J, model.J, model.A, rule=time_of_send_task_to) 131 | # model.time_of_send_task_to_other = Expression(model.J, model.A, rule=time_of_send_task_to_other) 132 | # model.time_of_received_task_from_other = Expression(model.J, model.A, 133 | # rule=time_of_received_task_from_other) 134 | model.time_of_deploy = Expression(model.J, model.A, rule=time_of_deploy) 135 | model.cost_of_deploy = Expression(model.J, model.A, rule=cost_of_deploy) 136 | model.time_of_process = Expression(model.J, model.A, rule=time_of_process) 137 | model.total_time_of_edge = Expression(model.J, rule=total_time_of_edge) 138 | model.total_cost_of_edge = Expression(model.J, rule=total_cost_of_edge) 139 | 140 | # 择一约束 141 | model.c1 = Constraint(model.I, rule=c1) 142 | # model.c2 = Constraint(model.A, model.J, model.J, rule=c2) 143 | # model.c3 = Constraint(model.J, model.A, rule=c3) 144 | # model.c41 = Constraint(model.A, model.J, model.J, rule=c41) 145 | # model.c42 = Constraint(model.A, model.J, model.J, rule=c42) 146 | # model.c5 = Constraint(model.J, model.A, rule=c5) # inf 147 | # model.c6 = Constraint(model.A, model.J, model.J, rule=c6) 148 | model.c71 = Constraint(model.A, model.J, rule=c71) 149 | model.c72 = Constraint(model.A, model.J, rule=c72) 150 | # model.c8 = Constraint(model.J, rule=self.c8) 151 | model.c9 = Constraint(model.J, rule=c9) 152 | model.c10 = Constraint(model.J, rule=c10) 153 | 154 | model.obj = Objective(rule=obj_rule, sense=minimize) 155 | 156 | return model 157 | 158 | def solve(self): 159 | model = self.create_model() 160 | opt = SolverFactory('scip') 161 | solution = opt.solve(model) 162 | # 输出求解结果 163 | # solution.write() 164 | 165 | x = { 166 | (i, j): value(model.x[i, j]) 167 | for i in model.I 168 | for j in model.J 169 | } 170 | 171 | y = { 172 | (j, k, a): 0 173 | for j in model.J 174 | for k in model.J 175 | for a in model.A 176 | } 177 | 178 | z = { 179 | (j, a): value(model.z[j, a]) 180 | for j in model.J 181 | for a in model.A 182 | } 183 | 184 | theta = { 185 | (j, k, a): 0 186 | for j in model.J 187 | for k in model.J 188 | for a in model.A 189 | } 190 | 191 | mu = { 192 | (j, a): value(model.mu[j, a]) 193 | for j in model.J 194 | for a in model.A 195 | } 196 | 197 | return x, y, z, theta, mu 198 | 199 | 200 | if __name__ == '__main__': 201 | pass 202 | -------------------------------------------------------------------------------- /core/decision_module/ec_schedul_model.py: -------------------------------------------------------------------------------- 1 | from pyomo.environ import ConcreteModel, Set, Var, Param, Expression, Objective, Constraint 2 | from pyomo.environ import Binary, Reals, minimize, SolverFactory, value 3 | 4 | 5 | class ECModel: 6 | def __init__(self): 7 | self.n_device = 0 8 | self.n_edge = 0 9 | self.n_app = 0 10 | 11 | self.delta = 0 12 | self.beta = 0.5 13 | 14 | self.C_u = {} 15 | self.C_d = {} 16 | self.C_a = [] 17 | self.C_c = [] 18 | 19 | self.p = {} 20 | self.L = {} 21 | self.R_off = {} 22 | self.R_sch = {} 23 | self.s = [] 24 | self.Ha = [] 25 | self.f = [] 26 | self.Hmax = [] 27 | 28 | self.queue_ = {} 29 | self.z_deploy_ = {} 30 | 31 | def set_parameter(self, **kwargs): 32 | self.n_device = kwargs["n_device"] 33 | self.n_edge = kwargs["n_edge"] 34 | self.n_app = kwargs["n_app"] 35 | 36 | self.delta = kwargs["delta"] 37 | self.beta = kwargs["beta"] 38 | 39 | self.C_u = {j: kwargs["C_u"][j] for j in range(self.n_edge)} # 应该修改为 C^u_{i,j} 40 | self.C_d = {(j, k): kwargs["C_d"][j][k] for j in range(self.n_edge) for k in range(self.n_edge)} 41 | self.C_a = kwargs["C_a"] 42 | self.C_c = kwargs["C_c"] 43 | 44 | ItoAmap = kwargs["ItoAmap"] 45 | for i in range(self.n_device): 46 | for a in range(self.n_app): 47 | if a == ItoAmap[i]: 48 | self.p[(i, a)] = 1 49 | else: 50 | self.p[(i, a)] = 1 51 | 52 | self.L = kwargs["L"] 53 | self.R_off = kwargs["r"] 54 | self.R_sch = kwargs["R"] 55 | self.s = kwargs["s"] 56 | self.Ha = kwargs["Ha"] 57 | self.f = kwargs["f"] 58 | self.Hmax = kwargs["Hmax"] 59 | 60 | self.queue_ = kwargs["queue_"] 61 | self.z_deploy_ = kwargs["y_deploy_"] 62 | 63 | def create_model(self): 64 | model = ConcreteModel() 65 | 66 | model.I = Set(initialize=range(self.n_device)) 67 | model.J = Set(initialize=range(self.n_edge)) 68 | model.A = Set(initialize=range(self.n_app)) 69 | model.delta = Param(initialize=self.delta) 70 | model.beta = Param(initialize=self.beta) 71 | 72 | model.x = Var(model.I, model.J, within=Binary) 73 | # model.y = Var(model.J, model.J, model.A, within=Binary) 74 | model.z = Var(model.J, model.A, within=Binary) 75 | model.theta = Var(model.J, model.J, model.A, within=Reals, bounds=[0, 1]) 76 | model.mu = Var(model.J, model.A, within=Reals, bounds=[0, 1]) 77 | 78 | model.C_u = Param(model.J, initialize=self.C_u) 79 | model.C_d = Param(model.J, model.J, initialize=self.C_d) 80 | model.C_a = Param(model.A, initialize=self.C_a) 81 | model.C_c = Param(model.J, initialize=self.C_c) 82 | model.p = Param(model.I, model.A, initialize=self.p) 83 | 84 | model.L = Param(model.I, model.A, initialize=self.L) 85 | model.R_off = Param(model.I, model.J, initialize=self.R_off) 86 | model.R_sch = Param(model.J, model.J, initialize=self.R_sch) 87 | model.s = Param(model.A, initialize=self.s) 88 | model.Ha = Param(model.A, initialize=self.Ha) 89 | model.f = Param(model.J, initialize=self.f) 90 | model.Hmax = Param(model.J, initialize=self.Hmax) 91 | 92 | model.queue_ = Param(model.J, model.A, initialize=self.queue_) 93 | model.z_deploy_ = Param(model.J, model.A, initialize=self.z_deploy_) # 修改 原 y 表示调度,z表示部署 94 | 95 | def offload_time_rule(mod, i, a): 96 | return sum( 97 | mod.x[i, j] * mod.L[i, a] / mod.R_off[i, j] 98 | for j in mod.J 99 | ) 100 | model.offload_time = Expression(model.I, model.A, rule=offload_time_rule) 101 | 102 | def task_offloaded_rule(mod, j, a): 103 | return sum( 104 | mod.L[i, a] * mod.x[i, j] 105 | for i in mod.I 106 | ) 107 | model.task_offloaded = Expression(model.J, model.A, rule=task_offloaded_rule) 108 | 109 | def time_of_task_offloaded_rule(mod, j, a): 110 | return sum( 111 | mod.L[i, a] * mod.x[i, j] / mod.R_off[i, j] 112 | for i in mod.I 113 | ) 114 | model.time_of_task_offloaded = Expression(model.J, model.A, rule=time_of_task_offloaded_rule) 115 | 116 | def send_task_amount_rule(mod, j, k, a): 117 | return mod.theta[j, k, a] * (mod.queue_[j, a] + mod.task_offloaded[j, a]) 118 | model.send_task_amount = Expression(model.J, model.J, model.A, rule=send_task_amount_rule) 119 | 120 | def task_send_to_other_rule(mod, j, a): 121 | return sum(mod.send_task_amount[j, k, a] for k in model.J) 122 | model.task_send_to_other = Expression(model.J, model.A, rule=task_send_to_other_rule) 123 | 124 | def task_received_from_other_rule(mod, j, a): 125 | return sum(mod.send_task_amount[k, j, a] for k in model.J) 126 | model.task_received_from_other = Expression(model.J, model.A, rule=task_received_from_other_rule) 127 | 128 | def queue_before_process_rule(mod, j, a): 129 | return mod.queue_[j, a] + mod.task_offloaded[j, a] + mod.task_received_from_other[j, a] \ 130 | - mod.task_send_to_other[j, a] 131 | model.queue_before_process = Expression(model.J, model.A, rule=queue_before_process_rule) 132 | 133 | def queue_after_process_rule(mod, j, a): 134 | return (1 - mod.mu[j, a]) * mod.queue_before_process[j, a] 135 | model.queue_after_process = Expression(model.J, model.A, rule=queue_after_process_rule) 136 | 137 | def send_time_rule(mod, j, k, a): 138 | return mod.send_task_amount[j, k, a] / mod.R_sch[j, k] 139 | model.send_time = Expression(model.J, model.J, model.A, rule=send_time_rule) 140 | 141 | def time_send_task_to_other_rule(mod, j, a): 142 | return sum(mod.send_time[j, k, a] for k in mod.J) 143 | model.time_send_task_to_other = Expression(model.J, model.A, rule=time_send_task_to_other_rule) 144 | 145 | def time_receive_task_from_other_rule(mod, j, a): 146 | return sum(mod.send_time[k, j, a] for k in mod.J) 147 | model.time_receive_task_from_other = Expression(model.J, model.A, rule=time_receive_task_from_other_rule) 148 | 149 | def time_of_deploy_rule(mod, j, a): 150 | return (1 - mod.z_deploy_[j, a]) * mod.s[a] * mod.z[j, a] 151 | model.time_of_deploy = Expression(model.J, model.A, rule=time_of_deploy_rule) 152 | 153 | def time_of_process_rule(mod, j, a): 154 | return mod.mu[j, a] * mod.queue_before_process[j, a] / model.f[j] # f 修改为 F_edge,增加本地计算能力 155 | model.time_of_process = Expression(model.J, model.A, rule=time_of_process_rule) 156 | 157 | def total_time_of_edge_rule(mod, j): 158 | return sum(mod.time_of_task_offloaded[j, a] for a in model.A) \ 159 | + sum(model.send_time[j, k, a] for a in model.A for k in model.J) \ 160 | + sum(model.send_time[k, j, a] for a in model.A for k in model.J) \ 161 | + sum(model.time_of_deploy[j, a] for a in model.A) \ 162 | + sum(model.time_of_process[j, a] for a in model.A) 163 | model.total_time_of_edge = Expression(model.J, rule=total_time_of_edge_rule) 164 | 165 | # 定义总的目标函数 166 | 167 | def obj_rule(mod): 168 | return mod.beta * sum(mod.queue_after_process[j, a] for a in mod.A for j in mod.J) \ 169 | + (1 - mod.beta) * (sum( 170 | mod.offload_time[i, a] for i in mod.I for a in mod.A) + sum( 171 | mod.send_time[j, k, a] for j in mod.J for k in mod.J for a in mod.A) + sum( 172 | mod.time_of_deploy[j, a] + mod.time_of_process[j, a] for j in mod.J for a in mod.A) 173 | ) 174 | model.obj = Objective(rule=obj_rule, sense=minimize) 175 | 176 | # 定义约束条件 177 | 178 | # 择一约束,用户关联约束 179 | def c1_rule(mod, i): 180 | return sum(mod.x[i, j] for j in mod.J) == 1 181 | model.c1 = Constraint(model.I, rule=c1_rule) 182 | 183 | # 发送比例总不能大于1 184 | def c5_rule(mod, j, a): 185 | return sum(mod.theta[j, k, a] for k in mod.J) <= 1 186 | model.c5 = Constraint(model.J, model.A, rule=c5_rule) 187 | 188 | # 处理比例控制 189 | def c7_rule(mod, j, a): 190 | return mod.mu[j, a] <= mod.z[j, a] 191 | model.c7 = Constraint(model.J, model.A, rule=c7_rule) 192 | 193 | # 放置资源约束 194 | def c9_rule(mod, j): 195 | return sum(mod.z[j, a] * mod.Ha[a] for a in mod.A) <= mod.Hmax[j] 196 | model.c9 = Constraint(model.J, rule=c9_rule) 197 | 198 | # 时延约束:每个边的运行时间要小于时隙长度 199 | def c10_rule(mod, j): 200 | return mod.total_time_of_edge[j] <= mod.delta 201 | model.c10 = Constraint(model.J, rule=c10_rule) 202 | 203 | return model 204 | 205 | def solve(self): 206 | model = self.create_model() 207 | opt = SolverFactory('scip') 208 | solution = opt.solve(model) 209 | # 输出求解结果 210 | # solution.write() 211 | 212 | x = { 213 | (i, j): value(model.x[i, j]) 214 | for i in model.I 215 | for j in model.J 216 | } 217 | 218 | y = { 219 | (j, k, a): 0 220 | for j in model.J 221 | for k in model.J 222 | for a in model.A 223 | } 224 | for j in model.J: 225 | for k in model.J: 226 | for a in model.A: 227 | if value(model.theta[j, k, a]) > 0: 228 | y[(j, k, a)] = 1 229 | 230 | z = { 231 | (j, a): value(model.z[j, a]) 232 | for j in model.J 233 | for a in model.A 234 | } 235 | 236 | theta = { 237 | (j, k, a): value(model.theta[j, k, a]) 238 | for j in model.J 239 | for k in model.J 240 | for a in model.A 241 | } 242 | 243 | mu = { 244 | (j, a): value(model.mu[j, a]) 245 | for j in model.J 246 | for a in model.A 247 | } 248 | 249 | return x, y, z, theta, mu 250 | 251 | -------------------------------------------------------------------------------- /core/decision_module/expression.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # @Time : 2023/10/23 15:52 4 | # @Author : zhangqi 5 | # @File : expression.py 6 | # @Software: PyCharm 7 | def upload_time(model, i, j): 8 | return sum(model.L[i, a] for a in model.A) * model.x[i, j] / model.r[i, j] 9 | 10 | 11 | def received_task(model, j, a): 12 | return sum(model.L[i, a] * model.x[i, j] for i in model.I) 13 | 14 | 15 | def send_task_to(model, j, k, a): 16 | return model.theta[j, k, a] * model.y[j, k, a] * (model.queue_[j, a] + model.received_task[j, a]) 17 | 18 | 19 | def received_task_from_other(model, j, a): 20 | return sum(model.send_task_to[k, j, a] for k in model.J if k != j) 21 | 22 | 23 | def send_task_to_other(model, j, a): 24 | return sum(model.send_task_to[j, k, a] for k in model.J if k != j) 25 | 26 | 27 | def queue_before_process(model, j, a): 28 | return model.queue_[j, a] + model.received_task[j, a] + model.received_task_from_other[j, a] - model.send_task_to_other[j, a] 29 | 30 | 31 | def queue_after_process(model, j, a): 32 | return (1 - model.mu[j, a]) * model.queue_before_process[j, a] 33 | 34 | 35 | def time_of_send_task_to(model, j, k, a): 36 | return model.send_task_to[j, k, a] / model.R[j, k] 37 | 38 | 39 | def time_of_send_task_to_other(model, j, a): 40 | return sum(model.time_of_send_task_to[j, k, a] for k in model.J if k != j) 41 | 42 | 43 | def time_of_received_task_from_other(model, j, a): 44 | return sum(model.time_of_send_task_to[k, j, a] for k in model.J if k != j) 45 | 46 | 47 | def time_of_deploy(model, j, a): 48 | return (1 - model.y_deploy_[j, a]) * model.s[a] * model.z[j, a] 49 | 50 | 51 | def cost_of_deploy(model, j, a): 52 | return (1 - model.y_deploy_[j, a]) * model.C_a[a] * model.z[j, a] 53 | 54 | 55 | def time_of_process(model, j, a): 56 | return model.mu[j, a] * model.queue_before_process[j, a] / model.f[j] 57 | 58 | 59 | # 择一约束,用户关联约束 60 | def c1(model, i): 61 | return sum(model.x[i, j] for j in model.J) == 1 62 | 63 | 64 | # 只有接受到了a才可以向其他边缘发送任务a 65 | def c2(model, a, j, k): 66 | return model.y[j, k, a] <= sum(model.p[i, a] * model.x[i, j] for i in model.I) 67 | 68 | 69 | # 最多选择一个边缘发送 70 | def c3(model, j, a): 71 | return sum(model.y[j, k, a] for k in model.J if k != j) <= 1 72 | 73 | 74 | # 发送比例控制 75 | def c41(model, a, j, k): 76 | N = 1000 77 | return model.theta[j, k, a] / N <= model.y[j, k, a] 78 | 79 | 80 | def c42(model, a, j, k): 81 | N = 1000 82 | return model.y[j, k, a] <= model.theta[j, k, a] * N 83 | 84 | 85 | # 发送比例总不能大于1 86 | def c5(model, j, a): 87 | return sum(model.theta[j, k, a] for k in model.J) <= 1 88 | 89 | 90 | # 只有边缘上部署了应用,才可以发送 91 | def c6(model, a, j, k): 92 | return model.y[j, k, a] <= model.z[k, a] 93 | 94 | 95 | # 处理比例控制 96 | def c71(model, a, k): 97 | N = 1 98 | return model.mu[k, a] / N <= model.z[k, a] 99 | 100 | 101 | def c72(model, a, k): 102 | N = 1 103 | return model.z[k, a] <= model.mu[k, a] * N 104 | 105 | 106 | def c8(model, j): 107 | return sum(model.mu[j, a] for a in model.A) <= 1 108 | 109 | 110 | # 放置资源约束 111 | def c9(model, j): 112 | return sum(model.z[j, a] * model.Ha[a] for a in model.A) <= model.Hmax[j] 113 | 114 | 115 | # 时延约束:每个边的运行时间要小于时隙长度 116 | def c10(model, j): 117 | return model.total_time_of_edge[j] <= model.delta 118 | 119 | 120 | def obj_rule(model): 121 | 122 | obj = 0 123 | queue_remain = 0 124 | sum_cost = 0 125 | for j in model.J: 126 | queue_remain += sum(model.queue_after_process[j, a] for a in model.A) 127 | sum_cost += model.total_cost_of_edge[j] 128 | 129 | obj += model.beta * queue_remain + (1 - model.beta) * sum_cost 130 | 131 | return obj 132 | -------------------------------------------------------------------------------- /core/env_module/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # @Time : 2023/10/19 18:13 4 | # @Author : zhangqi 5 | # @File : __init__.py.py 6 | # @Software: PyCharm 7 | -------------------------------------------------------------------------------- /core/env_module/__pycache__/__init__.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AtticusZhang/PyEdgeSim/683b90ed37f7a4531ea761d5fbe5ba17b1b82a3a/core/env_module/__pycache__/__init__.cpython-39.pyc -------------------------------------------------------------------------------- /core/env_module/__pycache__/environment.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AtticusZhang/PyEdgeSim/683b90ed37f7a4531ea761d5fbe5ba17b1b82a3a/core/env_module/__pycache__/environment.cpython-39.pyc -------------------------------------------------------------------------------- /core/env_module/__pycache__/environment.cpython-39_冲突文件_16964_20231020094222.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AtticusZhang/PyEdgeSim/683b90ed37f7a4531ea761d5fbe5ba17b1b82a3a/core/env_module/__pycache__/environment.cpython-39_冲突文件_16964_20231020094222.pyc -------------------------------------------------------------------------------- /core/env_module/environment.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # @Time : 2023/10/19 18:13 4 | # @Author : zhangqi 5 | # @File : environment.py 6 | # @Software: PyCharm 7 | import simpy 8 | 9 | 10 | class Env: 11 | def __init__(self): 12 | self.sim = simpy.Environment() 13 | 14 | def log(self, content): 15 | print(f"[{self.sim.now:.2f}]: {content}") 16 | -------------------------------------------------------------------------------- /core/orchestrator_module/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # @Time : 2023/10/19 16:28 4 | # @Author : zhangqi 5 | # @File : __init__.py.py 6 | # @Software: PyCharm 7 | -------------------------------------------------------------------------------- /core/orchestrator_module/__pycache__/__init__.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AtticusZhang/PyEdgeSim/683b90ed37f7a4531ea761d5fbe5ba17b1b82a3a/core/orchestrator_module/__pycache__/__init__.cpython-39.pyc -------------------------------------------------------------------------------- /core/orchestrator_module/__pycache__/orchestrator.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AtticusZhang/PyEdgeSim/683b90ed37f7a4531ea761d5fbe5ba17b1b82a3a/core/orchestrator_module/__pycache__/orchestrator.cpython-39.pyc -------------------------------------------------------------------------------- /core/orchestrator_module/__pycache__/orchestrator.cpython-39_冲突文件_16964_20231024000002.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AtticusZhang/PyEdgeSim/683b90ed37f7a4531ea761d5fbe5ba17b1b82a3a/core/orchestrator_module/__pycache__/orchestrator.cpython-39_冲突文件_16964_20231024000002.pyc -------------------------------------------------------------------------------- /core/orchestrator_module/orchestrator.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # @Time : 2023/10/19 16:30 4 | # @Author : zhangqi 5 | # @File : orchestrator.py 6 | # @Software: PyCharm 7 | import math 8 | 9 | from typing import List, Tuple, Dict 10 | 11 | import simpy 12 | 13 | from core.task_generator_module.task import Task 14 | from core.scenario_module.device import Device 15 | from core.task_generator_module.task_generator import TaskGenerator 16 | from core.scenario_module.scenario import Scenario 17 | from core.env_module.environment import Env 18 | # from core.decision_module.ec_model import ECModel 19 | from core.decision_module.ec_model_without_schedule import ECModel 20 | # from core.decision_module.ec_schedul_model import ECModel 21 | from core.task_generator_module.applications import Applications 22 | from core.simsetting_module.simsetting import simSetting, DEVICE_NAMES, EDGE_NAMES, APP_TYPES, ItoAmap 23 | 24 | 25 | class Orchestrator: 26 | 27 | def __init__(self): 28 | self.task_generator = TaskGenerator() 29 | self.scenario = Scenario() 30 | self.env = Env() 31 | self.ec_model = ECModel() 32 | self.t = 0 33 | 34 | def _allocate_task_on_device(self, task: Task, device: Device): 35 | device.tasks.append(task) 36 | self.env.log(f"Generate {task.get_process_data_size()} KB {task.get_type()} id-{task.get_id()} on {device.get_name()}") 37 | 38 | def gen_all_tasks_on_device(self): 39 | self.task_generator.task_count = 0 40 | while not self.task_generator.is_empty(): 41 | task = self.task_generator.random_generate_task_on_device(generate_time=self.env.sim.now) 42 | self._allocate_task_on_device(task, self.scenario.get_device(task.get_gen_device())) 43 | 44 | def _calculate_transfer_time(self, task: Task, src_name: str, dst_name: str): 45 | link = self.scenario.get_link(src_name, dst_name) 46 | return task.get_transfer_data_size() / link.get_transfer_rate() 47 | 48 | def _offload_tasks_from_device_to_edge(self, device_name: str, edge_name: str): 49 | device = self.scenario.get_device(device_name) 50 | edge = self.scenario.get_edge(edge_name) 51 | 52 | while len(device.tasks) > 0: 53 | task = device.tasks.pop() 54 | 55 | offload_cost_time = self._calculate_transfer_time(task, device_name, edge_name) 56 | yield self.env.sim.timeout(offload_cost_time) 57 | 58 | edge.add_task_to_queue(task.get_type(), task=task) 59 | self.env.log("-"*10 + f"{device_name} offload {task.get_type()} task id-{task.get_id()} to {edge_name}. [{offload_cost_time:.2f} s]") 60 | 61 | def offload_all_device_to_edge(self, offload_device_list: List, edge_name: str, offload_e: simpy.Event): 62 | event_list = [] 63 | for device_name in offload_device_list: 64 | event_list.append(self.env.sim.process(self._offload_tasks_from_device_to_edge(device_name, edge_name))) 65 | 66 | yield simpy.AllOf(self.env.sim, event_list) 67 | offload_e.succeed() 68 | 69 | def _schedule_tasks_between_edge(self, src_name, dst_name, task_type, schedule_ratio: float): 70 | src_edge = self.scenario.get_edge(src_name) 71 | dst_edge = self.scenario.get_edge(dst_name) 72 | 73 | n_schedule_task = math.ceil(len(src_edge.tasks[task_type]) * schedule_ratio) 74 | # print(f"n_schedule_task = {n_schedule_task}") 75 | 76 | while n_schedule_task > 0: 77 | task = src_edge.tasks[task_type].pop(0) 78 | 79 | schedule_cost_time = self._calculate_transfer_time(task, src_name, dst_name) 80 | yield self.env.sim.timeout(schedule_cost_time) 81 | 82 | dst_edge.add_task_to_queue(task_type, task=task) 83 | self.env.log("-"*20+f"{src_name} schedule {task_type} task id-{task.get_id()} slice-{task.get_slice_id()} to {dst_name}. [{schedule_cost_time:.2f} s]") 84 | 85 | n_schedule_task -= 1 86 | 87 | def schedule_all_task_to_other(self, src_name, schedule_list: List[Tuple[str, str, float]], 88 | offload_e: simpy.Event, schedule_e: simpy.Event): 89 | yield offload_e # 等待所有任务卸载完成 90 | 91 | event_list = [] 92 | for schedule in schedule_list: 93 | event_list.append(self.env.sim.process( 94 | self._schedule_tasks_between_edge(src_name, schedule[0], schedule[1], schedule[2]))) 95 | 96 | yield simpy.AllOf(self.env.sim, event_list) 97 | schedule_e.succeed() 98 | self.env.log("-"*20+f"{src_name} schedule complete!") 99 | 100 | def _deploy_app_on_edge(self, edge_name, app_type, deploy_resource: simpy.Resource): 101 | with deploy_resource.request() as req: 102 | yield req # 请求CPU资源 103 | 104 | edge = self.scenario.get_edge(edge_name) 105 | deploy_time = edge.deploy_app_cost_time(app_type) 106 | 107 | if deploy_time >= 0: 108 | yield self.env.sim.timeout(deploy_time) 109 | self.env.log("-"*30+f"App of {app_type} has deployed on {edge_name}. [{deploy_time:.2f} s]") 110 | else: 111 | self.env.log("-"*30+f"Failed to deploy app of {app_type} on {edge_name}.") 112 | 113 | def execute_deploy_decision_on_edge(self, edge_name, deploy_decision: List, schedule_e, deploy_e): 114 | yield schedule_e 115 | 116 | edge = self.scenario.get_edge(edge_name) 117 | 118 | for app_type in APP_TYPES: 119 | if app_type not in deploy_decision: 120 | edge.remove_app(app_type) 121 | 122 | event_list = [] 123 | deploy_resource = simpy.Resource(self.env.sim, capacity=1) 124 | for app_type in deploy_decision: 125 | event_list.append(self.env.sim.process(self._deploy_app_on_edge(edge_name, app_type, deploy_resource))) 126 | 127 | yield simpy.AllOf(self.env.sim, event_list) 128 | deploy_e.succeed() 129 | self.env.log("-"*30+f"{edge_name} deploy complete!") 130 | 131 | def _process_task_on_edge(self, edge_name, task_type, process_ratio: float, 132 | cpu_resource: simpy.Resource): 133 | with cpu_resource.request() as req: 134 | yield req # 请求CPU资源 135 | 136 | edge = self.scenario.get_edge(edge_name) 137 | n_process_task = math.floor(len(edge.tasks[task_type]) * process_ratio) 138 | 139 | if n_process_task > 0: 140 | while n_process_task > 0: 141 | task = edge.tasks[task_type].pop(0) 142 | 143 | process_cost_time = task.get_process_data_size() / edge.get_cpu() 144 | yield self.env.sim.timeout(process_cost_time) 145 | 146 | self.env.log("-"*40+f"{task_type} task id-{task.get_id()} slice-{task.get_slice_id()} has processed on {edge_name}. [{process_cost_time:.2f} s]") 147 | edge.log_processed_task(task, self.env.sim.now, edge_name) 148 | 149 | n_process_task -= 1 150 | 151 | def process_all_tasks_on_edge(self, edge_name, process_list: List[Tuple[str, float]], 152 | deploy_e: simpy.Event, process_e: simpy.Event): 153 | yield deploy_e 154 | 155 | cpu_resource = simpy.Resource(self.env.sim, capacity=1) 156 | event_list = [] 157 | for process in process_list: 158 | event_list.append( 159 | self.env.sim.process(self._process_task_on_edge(edge_name, process[0], process[1], cpu_resource)) 160 | ) 161 | 162 | yield simpy.AllOf(self.env.sim, event_list) 163 | process_e.succeed() 164 | self.env.log("-"*40+f"{edge_name} processed complete!") 165 | 166 | def get_task_info_for_model(self): 167 | task_amount_info = self.scenario.get_task_amount_info_of_all_device() 168 | 169 | l_for_model = {} 170 | for i, device_name in enumerate(DEVICE_NAMES): 171 | for a, app_type in enumerate(APP_TYPES): 172 | l_for_model[(i, a)] = task_amount_info[device_name][app_type] 173 | 174 | return l_for_model 175 | 176 | def get_offload_rate_for_model(self): 177 | transfer_rate_info = self.scenario.get_transfer_rate_from_device_to_edge() 178 | 179 | r_for_model = {} 180 | for i, device_name in enumerate(DEVICE_NAMES): 181 | for j, edge_name in enumerate(EDGE_NAMES): 182 | r_for_model[(i, j)] = transfer_rate_info[device_name][edge_name] 183 | 184 | return r_for_model 185 | 186 | def get_schedule_rate_for_model(self): 187 | schedule_rate_info = self.scenario.get_schedule_rate_between_edges() 188 | 189 | R_for_model = {} 190 | for j, src_edge_name in enumerate(EDGE_NAMES): 191 | for k, dst_edge_name in enumerate(EDGE_NAMES): 192 | R_for_model[(j, k)] = schedule_rate_info[src_edge_name][dst_edge_name] 193 | 194 | return R_for_model 195 | 196 | def get_edge_cpu_for_model(self): 197 | return [edge.get_cpu() for edge in self.scenario.get_all_edges()] 198 | 199 | def get_edge_max_deploy_for_model(self): 200 | return [edge.get_max_mem() for edge in self.scenario.get_all_edges()] 201 | 202 | def get_all_edge_queue_for_model(self): 203 | all_edge_queue_info = self.scenario.get_all_edge_queue_info() 204 | 205 | q_for_model = { 206 | (j, a): all_edge_queue_info[edge_name][app_type] 207 | for j, edge_name in enumerate(EDGE_NAMES) 208 | for a, app_type in enumerate(APP_TYPES) 209 | } 210 | 211 | return q_for_model 212 | 213 | def get_edge_deployed_info_for_model(self): 214 | all_edge_deployed_info = self.scenario.get_all_edge_deployed_info() 215 | 216 | y_deploy_for_model = { 217 | (j, a): all_edge_deployed_info[edge_name][app_type] 218 | for j, edge_name in enumerate(EDGE_NAMES) 219 | for a, app_type in enumerate(APP_TYPES) 220 | } 221 | 222 | return y_deploy_for_model 223 | 224 | def send_parameter_to_decision_module(self): 225 | devices = self.scenario.get_all_devices() 226 | edges = self.scenario.get_all_edges() 227 | apps = Applications().apps 228 | 229 | self.ec_model.set_parameter(n_device=len(devices), n_edge=len(edges), n_app=Applications().n_app, 230 | delta=simSetting.model_setting["delta"], 231 | beta=simSetting.model_setting["beta"], 232 | C_u=simSetting.model_setting["C_u"], 233 | C_d=simSetting.model_setting["C_d"], 234 | C_a=simSetting.model_setting["C_a"], 235 | C_c=simSetting.model_setting["C_c"], 236 | ItoAmap=ItoAmap, 237 | L=self.get_task_info_for_model(), 238 | r=self.get_offload_rate_for_model(), 239 | R=self.get_schedule_rate_for_model(), 240 | s=Applications().get_app_deploy_time_for_model(), 241 | Ha=Applications().get_app_mem_occupation(), 242 | f=self.get_edge_cpu_for_model(), 243 | Hmax=self.get_edge_max_deploy_for_model(), 244 | queue_=self.get_all_edge_queue_for_model(), 245 | y_deploy_=self.get_edge_deployed_info_for_model()) 246 | 247 | def get_decision_from_model(self): 248 | self.send_parameter_to_decision_module() 249 | x, y, z, theta, mu = self.ec_model.solve() 250 | # print(x) 251 | # print(y) 252 | # print(z) 253 | # print(theta) 254 | # print(mu) 255 | 256 | # format: {'E1': ['D1'], 'E2': ['D2', 'D3']} 257 | offload_decision = self._turn_x_to_offload_decision(x) 258 | # format: {'E1': [], 'E2': [('E1', 'A2', 0.24074074074074087)]} 259 | schedule_decision = self._turn_y_and_theta_to_schedule_decision(y, theta) 260 | # format: {'E1': ['A1', 'A2'], 'E2': ['A2']} 261 | # format: {} 262 | deploy_decision, process_decision = self._turn_z_mu_to_deploy_and_proocess_decision(z, mu) 263 | 264 | return offload_decision, schedule_decision, deploy_decision, process_decision 265 | 266 | def _turn_x_to_offload_decision(self, x): 267 | offload_decision = {edge_name: [] for edge_name in EDGE_NAMES} 268 | 269 | for i, device_name in enumerate(DEVICE_NAMES): 270 | for j, edge_name in enumerate(EDGE_NAMES): 271 | if abs(x[i, j] - 1) < 1e-4: 272 | offload_decision[edge_name].append(device_name) 273 | 274 | return offload_decision 275 | 276 | def _turn_y_and_theta_to_schedule_decision(self, y, theta): 277 | schedule_decision = {edge_name: [] for edge_name in EDGE_NAMES} 278 | 279 | for j, src_edge_name in enumerate(EDGE_NAMES): 280 | for k, dst_edge_name in enumerate(EDGE_NAMES): 281 | for a, app_type in enumerate(APP_TYPES): 282 | if abs(y[j, k, a] - 1) < 1e-4: 283 | schedule_decision[src_edge_name].append((dst_edge_name, app_type, theta[j, k, a])) 284 | 285 | return schedule_decision 286 | 287 | def _turn_z_mu_to_deploy_and_proocess_decision(self, z, mu): 288 | deploy_decision = {edge_name: [] for edge_name in EDGE_NAMES} 289 | process_decision = {edge_name: [] for edge_name in EDGE_NAMES} 290 | 291 | for j, edge_name in enumerate(EDGE_NAMES): 292 | for a, app_type in enumerate(APP_TYPES): 293 | if abs(z[j, a] - 1) < 1e-4: 294 | deploy_decision[edge_name].append(app_type) 295 | process_decision[edge_name].append((app_type, mu[j, a])) 296 | 297 | return deploy_decision, process_decision 298 | 299 | 300 | if __name__ == '__main__': 301 | pass 302 | -------------------------------------------------------------------------------- /core/scenario_module/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # @Time : 2023/10/19 10:35 4 | # @Author : zhangqi 5 | # @File : __init__.py.py 6 | # @Software: PyCharm 7 | -------------------------------------------------------------------------------- /core/scenario_module/__pycache__/__init__.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AtticusZhang/PyEdgeSim/683b90ed37f7a4531ea761d5fbe5ba17b1b82a3a/core/scenario_module/__pycache__/__init__.cpython-39.pyc -------------------------------------------------------------------------------- /core/scenario_module/__pycache__/device.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AtticusZhang/PyEdgeSim/683b90ed37f7a4531ea761d5fbe5ba17b1b82a3a/core/scenario_module/__pycache__/device.cpython-39.pyc -------------------------------------------------------------------------------- /core/scenario_module/__pycache__/edge.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AtticusZhang/PyEdgeSim/683b90ed37f7a4531ea761d5fbe5ba17b1b82a3a/core/scenario_module/__pycache__/edge.cpython-39.pyc -------------------------------------------------------------------------------- /core/scenario_module/__pycache__/link.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AtticusZhang/PyEdgeSim/683b90ed37f7a4531ea761d5fbe5ba17b1b82a3a/core/scenario_module/__pycache__/link.cpython-39.pyc -------------------------------------------------------------------------------- /core/scenario_module/__pycache__/node.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AtticusZhang/PyEdgeSim/683b90ed37f7a4531ea761d5fbe5ba17b1b82a3a/core/scenario_module/__pycache__/node.cpython-39.pyc -------------------------------------------------------------------------------- /core/scenario_module/__pycache__/offload_link.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AtticusZhang/PyEdgeSim/683b90ed37f7a4531ea761d5fbe5ba17b1b82a3a/core/scenario_module/__pycache__/offload_link.cpython-39.pyc -------------------------------------------------------------------------------- /core/scenario_module/__pycache__/scenario.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AtticusZhang/PyEdgeSim/683b90ed37f7a4531ea761d5fbe5ba17b1b82a3a/core/scenario_module/__pycache__/scenario.cpython-39.pyc -------------------------------------------------------------------------------- /core/scenario_module/__pycache__/schedule_link.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AtticusZhang/PyEdgeSim/683b90ed37f7a4531ea761d5fbe5ba17b1b82a3a/core/scenario_module/__pycache__/schedule_link.cpython-39.pyc -------------------------------------------------------------------------------- /core/scenario_module/device.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # @Time : 2023/10/19 10:57 4 | # @Author : zhangqi 5 | # @File : device.py 6 | # @Software: PyCharm 7 | import random 8 | 9 | from typing import List 10 | 11 | from core.scenario_module.node import Node, Location 12 | from core.task_generator_module.task import Task 13 | 14 | 15 | class Device(Node): 16 | 17 | def __init__(self, name, edge_location: Location): 18 | super(Device, self).__init__() 19 | self.device_name = name 20 | self.tasks: List[Task] = [] 21 | self.location = self._init_location(edge_location) 22 | 23 | def _init_location(self, e_location) -> Location: 24 | x = random.random() * 10 25 | y = random.random() * 10 26 | return Location(x + e_location.x, y + e_location.y) 27 | 28 | 29 | def get_name(self): 30 | return self.device_name 31 | 32 | 33 | if __name__ == '__main__': 34 | pass 35 | -------------------------------------------------------------------------------- /core/scenario_module/edge.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # @Time : 2023/10/19 11:00 4 | # @Author : zhangqi 5 | # @File : edge.py 6 | # @Software: PyCharm 7 | import copy 8 | 9 | from typing import Dict, List 10 | 11 | from core.task_generator_module.applications import Applications 12 | from core.simsetting_module.simsetting import simSetting 13 | from core.scenario_module.node import Node, Location 14 | from core.task_generator_module.task import Task 15 | 16 | 17 | def slice_task(task: Task): 18 | for i in range(task.get_process_data_size(), 0, -1): 19 | sliced_task = copy.deepcopy(task.get_info()) 20 | sliced_task.update({"slice_id": i}) 21 | sliced_task.update({"transfer_data_size": 1}) 22 | sliced_task.update({"process_data_size": 1}) 23 | yield Task(sliced_task) 24 | 25 | 26 | class Edge(Node): 27 | 28 | def __init__(self, info): 29 | super(Edge, self).__init__() 30 | self._info = info 31 | self.location = Location(info["location"][0], info["location"][1]) 32 | 33 | self.tasks: Dict[str, List[Task]] = self._init_tasks() 34 | self.done_task_info = [] 35 | self.deployed_app: List = self._info["deployed_app"] 36 | self.mem_used = 0 37 | 38 | def get_all_task_queue(self): 39 | return self.tasks 40 | 41 | def get_max_mem(self): 42 | return self._info["max_mem"] 43 | 44 | def get_name(self): 45 | return self._info["edge_name"] 46 | 47 | def get_cpu(self): 48 | return self._info["cpu_frequency"] 49 | 50 | def add_task_to_queue(self, task_type: str, task: Task): 51 | if task_type not in self.tasks.keys(): 52 | self.tasks[task_type] = [] 53 | 54 | self.tasks[task_type].append(task) 55 | # 暂时不使用分片 56 | # sliced_tasks_generator = slice_task(task) 57 | # for sliced_task in sliced_tasks_generator: 58 | # self.tasks[task_type].append(sliced_task) 59 | 60 | def log_processed_task(self, task: Task, processed_time, processed_device_name): 61 | task_processed_info = { 62 | "task_id": task.get_id(), 63 | "slice_id": task.get_slice_id(), 64 | "app_type": task.get_type(), 65 | "gen_device": task.get_gen_device(), 66 | "processed_device": processed_device_name, 67 | "generate_time": task.get_generate_time(), 68 | "processed_time": processed_time, 69 | "cost_time": processed_time - task.get_generate_time() 70 | } 71 | self.done_task_info.append(task_processed_info) 72 | 73 | def deploy_app_cost_time(self, task_type: str): 74 | if task_type in self.deployed_app: 75 | return 0 76 | else: 77 | if self.mem_used < self._info["max_mem"]: 78 | self.deployed_app.append(task_type) 79 | self.mem_used += simSetting.task_setting[task_type]["mem_occupation"] 80 | return simSetting.task_setting[task_type]["app_deploy_cost"] 81 | else: 82 | return -1 83 | 84 | def remove_app(self, task_type: str): 85 | if task_type in self.deployed_app: 86 | return self.deployed_app.remove(task_type) 87 | 88 | def _init_tasks(self) -> Dict[str, List[Task]]: 89 | tasks = {app_type: [] for app_type in Applications().app_types} 90 | 91 | for task_type, task_list in self._info["tasks"].items(): 92 | for task in task_list: 93 | tasks[task_type].append(Task(task)) 94 | 95 | return tasks 96 | 97 | 98 | if __name__ == '__main__': 99 | edge_info = simSetting.scenario_setting["E2"] 100 | edge = Edge(edge_info) 101 | print(edge.tasks) 102 | -------------------------------------------------------------------------------- /core/scenario_module/link.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # @Time : 2023/10/19 11:02 4 | # @Author : zhangqi 5 | # @File : link.py 6 | # @Software: PyCharm 7 | from abc import ABCMeta, abstractmethod 8 | 9 | 10 | class Link(metaclass=ABCMeta): 11 | 12 | def __init__(self): 13 | self._info = None 14 | self.src = None 15 | self.dst = None 16 | 17 | @abstractmethod 18 | def get_transfer_rate(self): 19 | pass 20 | -------------------------------------------------------------------------------- /core/scenario_module/node.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # @Time : 2023/10/19 10:45 4 | # @Author : zhangqi 5 | # @File : node.py 6 | # @Software: PyCharm 7 | import math 8 | 9 | from abc import ABCMeta, abstractmethod 10 | 11 | class Location(): 12 | def __init__(self, x, y): 13 | self.x = x 14 | self.y = y 15 | 16 | def distance_with(self, another_location): 17 | return math.sqrt((self.x - another_location.x) ** 2 + (self.y - another_location.y) ** 2) 18 | 19 | 20 | class Node(metaclass=ABCMeta): 21 | 22 | def __init__(self): 23 | self._info = None 24 | self.location = None 25 | 26 | @abstractmethod 27 | def get_name(self): 28 | pass 29 | -------------------------------------------------------------------------------- /core/scenario_module/offload_link.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # @Time : 2023/10/19 11:05 4 | # @Author : zhangqi 5 | # @File : offload_link.py 6 | # @Software: PyCharm 7 | import math 8 | 9 | from core.scenario_module.link import Link 10 | from core.scenario_module.device import Device 11 | from core.scenario_module.edge import Edge 12 | from core.simsetting_module.simsetting import simSetting 13 | 14 | 15 | class OffloadLink(Link): 16 | 17 | def __init__(self, device: Device, edge: Edge): 18 | super(OffloadLink, self).__init__() 19 | self.src = device 20 | self.dst = edge 21 | 22 | def get_transfer_rate(self): 23 | B = 1 # bandwidth 10^6 Hz = 1 MHz 24 | P_0 = 1 # transmit fixed power 1 Watt 25 | f_c = 915 # carrier frequency 915 MHz 26 | # distance between Device and edge server 27 | # d_M = self.src.location.distance_with(self.dst.location) 28 | d_M = 30 29 | A_d = 4.11 # antenna gain 4.11 30 | d_e = 2.6 # path loss exponent 31 | theta_2 = 1e-10 # receiver noise power 10^-10 Watt 32 | 33 | h = A_d * math.pow(3 * 1e8 / (4 * math.pi * f_c * d_M), d_e) 34 | 35 | R = B * math.log(1 + (P_0*h / theta_2), 2) / 8 36 | return R 37 | 38 | if __name__ == '__main__': 39 | D1_info = simSetting.scenario_setting["D1"] 40 | D2_info = simSetting.scenario_setting["D2"] 41 | E1_info = simSetting.scenario_setting["E1"] 42 | 43 | D1 = Device(D1_info) 44 | D2 = Device(D2_info) 45 | E1 = Edge(E1_info) 46 | 47 | d = E1.location.distance_with(D2.location) 48 | print(d) 49 | offload_link = OffloadLink(D1, E1) 50 | print(offload_link.get_transfer_rate()) 51 | -------------------------------------------------------------------------------- /core/scenario_module/scenario.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # @Time : 2023/10/19 11:14 4 | # @Author : zhangqi 5 | # @File : scenario.py 6 | # @Software: PyCharm 7 | import math 8 | import random 9 | 10 | import networkx as nx 11 | 12 | from typing import List, Dict 13 | 14 | from core.simsetting_module.simsetting import simSetting, DEVICE_NAMES, EDGE_NAMES, APP_TYPES 15 | from core.scenario_module.node import Node 16 | from core.scenario_module.edge import Edge 17 | from core.scenario_module.device import Device 18 | from core.scenario_module.link import Link 19 | from core.scenario_module.offload_link import OffloadLink 20 | from core.scenario_module.schedule_link import ScheduleLink 21 | from core.task_generator_module.task import Task 22 | 23 | scenario_setting = simSetting.scenario_setting 24 | 25 | 26 | class Scenario: 27 | 28 | def __init__(self): 29 | self._graph = nx.MultiDiGraph() 30 | self._init_node() 31 | self._init_link() 32 | 33 | def get_all_edge_deployed_info(self): 34 | all_edge_deployed_info = { 35 | edge_name: { 36 | app_type: 1 if app_type in self.get_edge(edge_name).deployed_app 37 | else 0 38 | for app_type in APP_TYPES 39 | } 40 | for edge_name in EDGE_NAMES 41 | } 42 | 43 | return all_edge_deployed_info 44 | 45 | def get_all_edge_queue_info(self): 46 | return {edge_name: self.get_edge_queue_info(edge_name) for edge_name in EDGE_NAMES} 47 | 48 | def get_edge_queue_info(self, edge_name) -> Dict[str, float]: 49 | self.get_edge(edge_name) 50 | all_task_queue: Dict[str, List[Task]] = self.get_edge(edge_name).get_all_task_queue() 51 | 52 | edge_queue_info = {app_type: 0 for app_type in APP_TYPES} 53 | 54 | for app_type, task_queue in all_task_queue.items(): 55 | for task in task_queue: 56 | edge_queue_info[app_type] += task.get_process_data_size() 57 | 58 | return edge_queue_info 59 | 60 | def get_schedule_rate_between_edges(self): 61 | schedule_rate_info = { 62 | src_edge_name: { 63 | dst_edge_name: math.inf if src_edge_name == dst_edge_name 64 | else self.get_link(src_edge_name, dst_edge_name).get_transfer_rate() 65 | for dst_edge_name in EDGE_NAMES 66 | } for src_edge_name in EDGE_NAMES 67 | } 68 | 69 | return schedule_rate_info 70 | 71 | def get_transfer_rate_from_device_to_edge(self): 72 | transfer_rate_info = { 73 | device_name: { 74 | edge_name: self.get_link(device_name, edge_name).get_transfer_rate() 75 | for edge_name in EDGE_NAMES 76 | } for device_name in DEVICE_NAMES 77 | } 78 | 79 | return transfer_rate_info 80 | 81 | def get_task_amount_info_of_all_device(self): 82 | task_amount_on_device = { 83 | device_name: { 84 | app_type: 0 for app_type in APP_TYPES 85 | } for device_name in DEVICE_NAMES 86 | } 87 | 88 | for device_name in DEVICE_NAMES: 89 | task_info_list = self._get_task_info_from_device(device_name) 90 | for task_info in task_info_list: 91 | task_amount_on_device[task_info["gen_device"]][task_info["app_type"]] += task_info["process_data_size"] 92 | 93 | return task_amount_on_device 94 | 95 | def _get_task_info_from_device(self, device_name): 96 | device = self.get_device(device_name) 97 | 98 | task_info_list = [] 99 | for task in device.tasks: 100 | task_info_list.append(task.get_info()) 101 | 102 | return task_info_list 103 | 104 | def get_all_devices(self) -> List[Device]: 105 | devices: List[Device] = [v['data'] for _, v in self._graph.nodes(data=True) if v['category'] == 'Device'] 106 | return devices 107 | 108 | def get_all_edges(self) -> List[Edge]: 109 | edges: List[Edge] = [v['data'] for _, v in self._graph.nodes(data=True) if v['category'] == 'Edge'] 110 | return edges 111 | 112 | def get_device(self, name: str) -> Device: 113 | return self._graph.nodes[name]["data"] 114 | 115 | def get_edge(self, name: str) -> Edge: 116 | return self._graph.nodes[name]["data"] 117 | 118 | def get_link(self, src_name: str, dst_name: str) -> Link: 119 | return self._graph.edges[src_name, dst_name, 0]["data"] 120 | 121 | def _add_device_node(self, node: Node): 122 | if node.get_name() not in self._graph: 123 | self._graph.add_node(node.get_name(), data=node, category="Device") 124 | 125 | def _add_edge_node(self, node: Node): 126 | if node.get_name() not in self._graph: 127 | self._graph.add_node(node.get_name(), data=node, category="Edge") 128 | 129 | def _add_offload_link(self, link: OffloadLink): 130 | self._graph.add_edge(link.src.get_name(), link.dst.get_name(), data=link) 131 | 132 | def _add_schedule_link(self, link: ScheduleLink): 133 | self._graph.add_edge(link.src, link.dst, data=link) 134 | self._graph.add_edge(link.dst, link.src, data=link) 135 | 136 | def _init_node(self): 137 | for j in range(1, scenario_setting["n_edge"] + 1): 138 | self._add_edge_node(Edge(scenario_setting["E" + str(j)])) 139 | 140 | for device_name in DEVICE_NAMES: 141 | # 这里按照不均匀分布在边缘附近生成设备 142 | seed = random.random() 143 | if seed < 0.5: 144 | choice_edge = self.get_edge(EDGE_NAMES[0]) 145 | else: 146 | choice_edge = self.get_edge(random.sample(EDGE_NAMES,1)[0]) 147 | 148 | self._add_device_node(Device(device_name, choice_edge.location)) 149 | 150 | def _init_link(self): 151 | for device_name in DEVICE_NAMES: 152 | for edge_name in EDGE_NAMES: 153 | device = self.get_device(device_name) 154 | edge = self.get_edge(edge_name) 155 | self._add_offload_link(OffloadLink(device, edge)) 156 | 157 | for j in range(1, scenario_setting["n_schedule_link"] + 1): 158 | self._add_schedule_link(ScheduleLink(scenario_setting["SL" + str(j)])) 159 | 160 | 161 | if __name__ == '__main__': 162 | scen = Scenario() 163 | ol = scen.get_device("D1") 164 | print(ol.location.x, ol.location.y) 165 | -------------------------------------------------------------------------------- /core/scenario_module/schedule_link.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # @Time : 2023/10/19 11:09 4 | # @Author : zhangqi 5 | # @File : schedule_link.py 6 | # @Software: PyCharm 7 | from core.scenario_module.link import Link 8 | 9 | 10 | class ScheduleLink(Link): 11 | 12 | def __init__(self, sl_info): 13 | super(ScheduleLink, self).__init__() 14 | self._info = sl_info 15 | self.src = sl_info["edge_names"][0] 16 | self.dst = sl_info["edge_names"][1] 17 | 18 | def get_transfer_rate(self): 19 | return self._info["transfer_rate"] 20 | -------------------------------------------------------------------------------- /core/simsetting_module/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # @Time : 2023/10/18 23:20 4 | # @Author : zhangqi 5 | # @File : __init__.py.py 6 | # @Software: PyCharm 7 | -------------------------------------------------------------------------------- /core/simsetting_module/__pycache__/__init__.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AtticusZhang/PyEdgeSim/683b90ed37f7a4531ea761d5fbe5ba17b1b82a3a/core/simsetting_module/__pycache__/__init__.cpython-39.pyc -------------------------------------------------------------------------------- /core/simsetting_module/__pycache__/simsetting.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AtticusZhang/PyEdgeSim/683b90ed37f7a4531ea761d5fbe5ba17b1b82a3a/core/simsetting_module/__pycache__/simsetting.cpython-39.pyc -------------------------------------------------------------------------------- /core/simsetting_module/__pycache__/simsetting.cpython-39_冲突文件_16964_20231022140805.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AtticusZhang/PyEdgeSim/683b90ed37f7a4531ea761d5fbe5ba17b1b82a3a/core/simsetting_module/__pycache__/simsetting.cpython-39_冲突文件_16964_20231022140805.pyc -------------------------------------------------------------------------------- /core/simsetting_module/__pycache__/simsetting.cpython-39_冲突文件_16964_20231024000002.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AtticusZhang/PyEdgeSim/683b90ed37f7a4531ea761d5fbe5ba17b1b82a3a/core/simsetting_module/__pycache__/simsetting.cpython-39_冲突文件_16964_20231024000002.pyc -------------------------------------------------------------------------------- /core/simsetting_module/json_files/model_setting.json: -------------------------------------------------------------------------------- 1 | { 2 | "delta": 10, 3 | "beta": 0.9, 4 | "C_u": [ 5 | [1, 1], 6 | [1, 1], 7 | [1, 1] 8 | ], 9 | "C_d": [ 10 | [1, 1], 11 | [1, 1] 12 | ], 13 | "C_a": [1, 1], 14 | "C_c": [1, 1], 15 | "ItoAmap": [0,1,1] 16 | } -------------------------------------------------------------------------------- /core/simsetting_module/json_files/scenario_setting.json: -------------------------------------------------------------------------------- 1 | { 2 | "n_device": 3, 3 | 4 | "device_name_list": ["D1", "D2", "D3"], 5 | 6 | "D1": { 7 | "device_name": "D1" 8 | }, 9 | "D2": { 10 | "device_name": "D2" 11 | }, 12 | "D3": { 13 | "device_name": "D3" 14 | }, 15 | 16 | "n_edge": 2, 17 | 18 | "edge_name_list": ["E1", "E2"], 19 | 20 | "E1": { 21 | "edge_name": "E1", 22 | "cpu_frequency": 1, 23 | "max_mem": 3, 24 | "deployed_app": ["A1", "A2"], 25 | "tasks": { 26 | "A1": [ 27 | { 28 | "generate_time": 0, 29 | "app_type": "A1", 30 | "task_id": 1, 31 | "slice_id": 2, 32 | "gen_device": "D1", 33 | "transfer_data_size": 1, 34 | "process_data_size": 1 35 | }, 36 | { 37 | "generate_time": 0, 38 | "app_type": "A1", 39 | "task_id": 1, 40 | "slice_id": 1, 41 | "gen_device": "D1", 42 | "transfer_data_size": 1, 43 | "process_data_size": 1 44 | } 45 | ] 46 | } 47 | }, 48 | "E2": { 49 | "edge_name": "E2", 50 | "cpu_frequency": 1, 51 | "max_mem": 3, 52 | "deployed_app": ["A2"], 53 | "tasks": { 54 | "A2": [ 55 | { 56 | "generate_time": 0, 57 | "app_type": "A2", 58 | "task_id": 2, 59 | "slice_id": 6, 60 | "gen_device": "D1", 61 | "transfer_data_size": 1, 62 | "process_data_size": 1 63 | }, 64 | { 65 | "generate_time": 0, 66 | "app_type": "A2", 67 | "task_id": 2, 68 | "slice_id": 5, 69 | "gen_device": "D1", 70 | "transfer_data_size": 1, 71 | "process_data_size": 1 72 | }, 73 | { 74 | "generate_time": 0, 75 | "app_type": "A2", 76 | "task_id": 2, 77 | "slice_id": 4, 78 | "gen_device": "D1", 79 | "transfer_data_size": 1, 80 | "process_data_size": 1 81 | }, 82 | { 83 | "generate_time": 0, 84 | "app_type": "A2", 85 | "task_id": 2, 86 | "slice_id": 3, 87 | "gen_device": "D1", 88 | "transfer_data_size": 1, 89 | "process_data_size": 1 90 | }, 91 | { 92 | "generate_time": 0, 93 | "app_type": "A2", 94 | "task_id": 2, 95 | "slice_id": 2, 96 | "gen_device": "D1", 97 | "transfer_data_size": 1, 98 | "process_data_size": 1 99 | }, 100 | { 101 | "generate_time": 0, 102 | "app_type": "A2", 103 | "task_id": 2, 104 | "slice_id": 1, 105 | "gen_device": "D1", 106 | "transfer_data_size": 1, 107 | "process_data_size": 1 108 | } 109 | ] 110 | } 111 | }, 112 | 113 | "n_schedule_link": 1, 114 | 115 | "SL1": { 116 | "edge_names": ["E1", "E2"], 117 | "transfer_rate": 10 118 | } 119 | } 120 | 121 | -------------------------------------------------------------------------------- /core/simsetting_module/json_files/tasks_setting.json: -------------------------------------------------------------------------------- 1 | { 2 | "n_time": 10, 3 | 4 | "n_app": 2, 5 | 6 | "app_type": ["A1", "A2"], 7 | 8 | "A1": { 9 | "app_deploy_cost": 1, 10 | "mem_occupation": 1 11 | }, 12 | "A2": { 13 | "app_deploy_cost": 1, 14 | "mem_occupation": 1 15 | }, 16 | 17 | "n_task": 8, 18 | 19 | "generate_probability": [0.25, 0.5, 1], 20 | 21 | "transfer_data_size": 1, 22 | 23 | "process_data_size": 1, 24 | 25 | "task1": { 26 | "generate_time": 0, 27 | "task_id": 3, 28 | "slice_id": 1, 29 | "app_type": "A1", 30 | "gen_device": "D1", 31 | "transfer_data_size": 1, 32 | "process_data_size": 1 33 | }, 34 | "task2": { 35 | "generate_time": 0, 36 | "task_id": 3, 37 | "slice_id": 2, 38 | "app_type": "A1", 39 | "gen_device": "D1", 40 | "transfer_data_size": 1, 41 | "process_data_size": 1 42 | }, 43 | "task3": { 44 | "generate_time": 0, 45 | "task_id": 4, 46 | "slice_id": 1, 47 | "app_type": "A2", 48 | "gen_device": "D3", 49 | "transfer_data_size": 1, 50 | "process_data_size": 1 51 | }, 52 | "task4": { 53 | "generate_time": 0, 54 | "task_id": 4, 55 | "slice_id": 2, 56 | "app_type": "A2", 57 | "gen_device": "D3", 58 | "transfer_data_size": 1, 59 | "process_data_size": 1 60 | }, 61 | "task5": { 62 | "generate_time": 0, 63 | "task_id": 4, 64 | "slice_id": 3, 65 | "app_type": "A2", 66 | "gen_device": "D3", 67 | "transfer_data_size": 1, 68 | "process_data_size": 1 69 | }, 70 | "task6": { 71 | "generate_time": 0, 72 | "task_id": 4, 73 | "slice_id": 4, 74 | "app_type": "A2", 75 | "gen_device": "D3", 76 | "transfer_data_size": 1, 77 | "process_data_size": 1 78 | }, 79 | "task7": { 80 | "generate_time": 0, 81 | "task_id": 4, 82 | "slice_id": 5, 83 | "app_type": "A2", 84 | "gen_device": "D3", 85 | "transfer_data_size": 1, 86 | "process_data_size": 1 87 | }, 88 | "task8": { 89 | "generate_time": 0, 90 | "task_id": 4, 91 | "slice_id": 6, 92 | "app_type": "A2", 93 | "gen_device": "D3", 94 | "transfer_data_size": 1, 95 | "process_data_size": 1 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /core/simsetting_module/json_files_1/model_setting.json: -------------------------------------------------------------------------------- 1 | { 2 | "delta": 10, 3 | "beta": 0.9, 4 | "C_u": [1,1,1,1], 5 | "C_d": [ 6 | [1, 1, 1, 1], 7 | [1, 1, 1, 1], 8 | [1, 1, 1, 1], 9 | [1, 1, 1, 1] 10 | ], 11 | "C_a": [1, 1, 1, 1, 1, 1, 1, 1, 1, 1], 12 | "C_c": [1, 1, 1] 13 | } -------------------------------------------------------------------------------- /core/simsetting_module/json_files_1/scenario_setting.json: -------------------------------------------------------------------------------- 1 | { 2 | "n_device": 4, 3 | 4 | "n_edge": 3, 5 | 6 | "E1": { 7 | "edge_name": "E1", 8 | "location": [0, 0], 9 | "cpu_frequency": 1, 10 | "max_mem": 3, 11 | "deployed_app": ["A1", "A3"], 12 | "tasks": {} 13 | }, 14 | "E2": { 15 | "edge_name": "E2", 16 | "location": [1000, 1000], 17 | "cpu_frequency": 1, 18 | "max_mem": 3, 19 | "deployed_app": ["A2"], 20 | "tasks": {} 21 | }, 22 | "E3": { 23 | "edge_name": "E3", 24 | "location": [0, 1000], 25 | "cpu_frequency": 1, 26 | "max_mem": 3, 27 | "deployed_app": ["A1", "A2"], 28 | "tasks": {} 29 | }, 30 | "E4": { 31 | "edge_name": "E4", 32 | "location": [1000, 0], 33 | "cpu_frequency": 1, 34 | "max_mem": 3, 35 | "deployed_app": ["A2"], 36 | "tasks": {} 37 | }, 38 | 39 | "n_schedule_link": 3, 40 | 41 | "SL1": { 42 | "edge_names": ["E1", "E2"], 43 | "transfer_rate": 10 44 | }, 45 | "SL2": { 46 | "edge_names": ["E1", "E3"], 47 | "transfer_rate": 10 48 | }, 49 | "SL3": { 50 | "edge_names": ["E2", "E3"], 51 | "transfer_rate": 10 52 | }, 53 | "SL4": { 54 | "edge_names": ["E1", "E4"], 55 | "transfer_rate": 10 56 | }, 57 | "SL5": { 58 | "edge_names": ["E2", "E4"], 59 | "transfer_rate": 10 60 | }, 61 | "SL6": { 62 | "edge_names": ["E3", "E4"], 63 | "transfer_rate": 10 64 | } 65 | } 66 | 67 | -------------------------------------------------------------------------------- /core/simsetting_module/json_files_1/tasks_setting.json: -------------------------------------------------------------------------------- 1 | { 2 | "n_time": 10, 3 | 4 | "n_app": 10, 5 | 6 | "n_task": 20, 7 | 8 | "transfer_data_size": 1, 9 | 10 | "process_data_size": 1, 11 | 12 | "A1": { 13 | "app_deploy_cost": 1, 14 | "mem_occupation": 1 15 | }, 16 | "A2": { 17 | "app_deploy_cost": 1, 18 | "mem_occupation": 1 19 | }, 20 | 21 | "A3": { 22 | "app_deploy_cost": 1, 23 | "mem_occupation": 1 24 | }, 25 | "A4": { 26 | "app_deploy_cost": 1, 27 | "mem_occupation": 1 28 | }, 29 | "A5": { 30 | "app_deploy_cost": 1, 31 | "mem_occupation": 1 32 | }, 33 | "A6": { 34 | "app_deploy_cost": 1, 35 | "mem_occupation": 1 36 | }, 37 | "A7": { 38 | "app_deploy_cost": 1, 39 | "mem_occupation": 1 40 | }, 41 | 42 | "A8": { 43 | "app_deploy_cost": 1, 44 | "mem_occupation": 1 45 | }, 46 | "A9": { 47 | "app_deploy_cost": 1, 48 | "mem_occupation": 1 49 | }, 50 | "A10": { 51 | "app_deploy_cost": 1, 52 | "mem_occupation": 1 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /core/simsetting_module/simsetting.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # @Time : 2023/10/18 23:22 4 | # @Author : zhangqi 5 | # @File : simsetting.py 6 | # @Software: PyCharm 7 | import json 8 | import os 9 | 10 | current_file_path = os.path.abspath(__file__) 11 | current_dir = os.path.dirname(current_file_path) 12 | json_files_path = os.path.join(current_dir, 'json_files_1') 13 | 14 | 15 | def read_json_file(json_path): 16 | with open(json_path) as json_file: 17 | config = json.load(json_file) 18 | return config 19 | 20 | 21 | class SimSetting: 22 | 23 | def __init__(self, tasks_setting, scenario_setting, model_setting): 24 | self.task_setting = read_json_file(tasks_setting) 25 | self.scenario_setting = read_json_file(scenario_setting) 26 | self.model_setting = read_json_file(model_setting) 27 | 28 | 29 | tasks_setting_path = os.path.join(json_files_path, 'tasks_setting.json') 30 | scenario_setting_path = os.path.join(json_files_path, 'scenario_setting.json') 31 | model_setting_path = os.path.join(json_files_path, 'model_setting.json') 32 | 33 | simSetting = SimSetting(tasks_setting_path, scenario_setting_path, model_setting_path) 34 | 35 | DEVICE_NAMES = ["D" + str(i) for i in range(1, simSetting.scenario_setting["n_device"] + 1)] 36 | EDGE_NAMES = ["E" + str(j) for j in range(1, simSetting.scenario_setting["n_edge"] + 1)] 37 | APP_TYPES = ["A" + str(a) for a in range(1, simSetting.task_setting["n_app"] + 1)] 38 | 39 | ItoAmap = [i % len(APP_TYPES) for i in range(len(DEVICE_NAMES))] 40 | 41 | if __name__ == '__main__': 42 | # print(simSetting.task_setting) 43 | # print(simSetting.scenario_setting) 44 | # print(simSetting.model_setting) 45 | # 46 | # c_u = simSetting.model_setting["C_u"] 47 | # 48 | # print(c_u[1][1]) 49 | print(ItoAmap) 50 | -------------------------------------------------------------------------------- /core/task_generator_module/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # @Time : 2023/10/18 23:47 4 | # @Author : zhangqi 5 | # @File : __init__.py.py 6 | # @Software: PyCharm 7 | -------------------------------------------------------------------------------- /core/task_generator_module/__pycache__/__init__.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AtticusZhang/PyEdgeSim/683b90ed37f7a4531ea761d5fbe5ba17b1b82a3a/core/task_generator_module/__pycache__/__init__.cpython-39.pyc -------------------------------------------------------------------------------- /core/task_generator_module/__pycache__/app.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AtticusZhang/PyEdgeSim/683b90ed37f7a4531ea761d5fbe5ba17b1b82a3a/core/task_generator_module/__pycache__/app.cpython-39.pyc -------------------------------------------------------------------------------- /core/task_generator_module/__pycache__/applications.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AtticusZhang/PyEdgeSim/683b90ed37f7a4531ea761d5fbe5ba17b1b82a3a/core/task_generator_module/__pycache__/applications.cpython-39.pyc -------------------------------------------------------------------------------- /core/task_generator_module/__pycache__/task.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AtticusZhang/PyEdgeSim/683b90ed37f7a4531ea761d5fbe5ba17b1b82a3a/core/task_generator_module/__pycache__/task.cpython-39.pyc -------------------------------------------------------------------------------- /core/task_generator_module/__pycache__/task_generator.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AtticusZhang/PyEdgeSim/683b90ed37f7a4531ea761d5fbe5ba17b1b82a3a/core/task_generator_module/__pycache__/task_generator.cpython-39.pyc -------------------------------------------------------------------------------- /core/task_generator_module/__pycache__/task_generator.cpython-39_冲突文件_16964_20231024000002.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AtticusZhang/PyEdgeSim/683b90ed37f7a4531ea761d5fbe5ba17b1b82a3a/core/task_generator_module/__pycache__/task_generator.cpython-39_冲突文件_16964_20231024000002.pyc -------------------------------------------------------------------------------- /core/task_generator_module/app.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # @Time : 2023/10/19 0:05 4 | # @Author : zhangqi 5 | # @File : app.py 6 | # @Software: PyCharm 7 | 8 | class App: 9 | 10 | def __init__(self, info): 11 | self._info = info 12 | 13 | def get_app_deploy_cost(self): 14 | return self._info["app_deploy_cost"] 15 | 16 | def get_mem_occupation(self): 17 | return self._info["mem_occupation"] 18 | -------------------------------------------------------------------------------- /core/task_generator_module/applications.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # @Time : 2023/10/19 0:06 4 | # @Author : zhangqi 5 | # @File : applications.py 6 | # @Software: PyCharm 7 | from core.simsetting_module.simsetting import simSetting, APP_TYPES 8 | from core.task_generator_module.app import App 9 | 10 | 11 | class Applications: 12 | _instance = None 13 | 14 | def __new__(cls, *args, **kwargs): 15 | if not cls._instance: 16 | cls._instance = super().__new__(cls) 17 | return cls._instance 18 | 19 | def __init__(self): 20 | self.n_app = simSetting.task_setting["n_app"] 21 | self.app_types = APP_TYPES 22 | self.apps = [App(simSetting.task_setting["A"+str(a)]) for a in range(1, self.n_app+1)] 23 | 24 | def get_app_deploy_time_for_model(self): 25 | return [app.get_app_deploy_cost() for app in self.apps] 26 | 27 | def get_app_mem_occupation(self): 28 | return [app.get_mem_occupation() for app in self.apps] 29 | 30 | 31 | if __name__ == '__main__': 32 | print(Applications().get_app_mem_occupation()) 33 | -------------------------------------------------------------------------------- /core/task_generator_module/task.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # @Time : 2023/10/18 23:49 4 | # @Author : zhangqi 5 | # @File : task.py 6 | # @Software: PyCharm 7 | from typing import Dict 8 | 9 | 10 | class Task: 11 | 12 | def __init__(self, info): 13 | self._info = info 14 | 15 | def get_id(self): 16 | return self._info["task_id"] 17 | 18 | def get_slice_id(self): 19 | return self._info["slice_id"] 20 | 21 | def get_type(self): 22 | return self._info["app_type"] 23 | 24 | def get_generate_time(self): 25 | return self._info["generate_time"] 26 | 27 | def get_gen_device(self): 28 | return self._info["gen_device"] 29 | 30 | def get_transfer_data_size(self): 31 | return self._info["transfer_data_size"] 32 | 33 | def get_process_data_size(self): 34 | return self._info["process_data_size"] 35 | 36 | def get_info(self) -> Dict: 37 | return self._info 38 | -------------------------------------------------------------------------------- /core/task_generator_module/task_generator.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # @Time : 2023/10/19 10:42 4 | # @Author : zhangqi 5 | # @File : task_generator.py 6 | # @Software: PyCharm 7 | import random 8 | 9 | from core.task_generator_module.task import Task 10 | from core.simsetting_module.simsetting import simSetting, DEVICE_NAMES, EDGE_NAMES, APP_TYPES, ItoAmap 11 | from core.scenario_module.scenario import Scenario 12 | 13 | n_task = simSetting.task_setting["n_task"] 14 | 15 | class TaskGenerator: 16 | 17 | def __init__(self): 18 | self.task_count = 0 19 | 20 | def is_empty(self) -> bool: 21 | return self.task_count >= n_task 22 | 23 | def generator_task(self, **kwargs) -> Task: 24 | self.task_count += 1 25 | task_info = { 26 | "generate_time": kwargs["generate_time"], 27 | "task_id": self.task_count, 28 | "slice_id": -1, 29 | "app_type": kwargs["app_type"], 30 | "gen_device": kwargs["gen_device"], 31 | "transfer_data_size": kwargs["transfer_data_size"], 32 | "process_data_size": kwargs["process_data_size"] 33 | } 34 | return Task(task_info) 35 | 36 | def random_generate_task_on_device(self, generate_time): 37 | device_name = random.sample(DEVICE_NAMES, 1)[0] 38 | 39 | return self.generator_task(generate_time=generate_time, 40 | app_type=APP_TYPES[ItoAmap[DEVICE_NAMES.index(device_name)]], 41 | gen_device=device_name, 42 | transfer_data_size=simSetting.task_setting["transfer_data_size"], 43 | process_data_size=simSetting.task_setting["process_data_size"]) 44 | 45 | 46 | if __name__ == '__main__': 47 | gen = TaskGenerator() 48 | count_D1 = 0 49 | count_D2 = 0 50 | count_D3 = 0 51 | while not gen.is_empty(): 52 | task = gen.random_generate_task_on_device(0) 53 | if task.get_gen_device() == "D1": 54 | count_D1 += 1 55 | elif task.get_gen_device() == "D2": 56 | count_D2 += 1 57 | else: 58 | count_D3 += 1 59 | 60 | print(count_D1 / simSetting.task_setting["n_task"]) 61 | print(count_D2 / simSetting.task_setting["n_task"]) 62 | print(count_D3 / simSetting.task_setting["n_task"]) 63 | -------------------------------------------------------------------------------- /simulation_examples/example_1/main.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # @Time : 2023/10/23 16:22 4 | # @Author : zhangqi 5 | # @File : main.py 6 | # @Software: PyCharm 7 | import simpy 8 | import pandas as pd 9 | 10 | from datetime import datetime 11 | 12 | from core.orchestrator_module.orchestrator import Orchestrator 13 | from core.simsetting_module.simsetting import simSetting, DEVICE_NAMES, EDGE_NAMES, APP_TYPES, ItoAmap 14 | 15 | 16 | def main(): 17 | orc = Orchestrator() 18 | while orc.t < 20: 19 | orc.gen_all_tasks_on_device() 20 | off_e = [simpy.Event(orc.env.sim) for _ in range(len(EDGE_NAMES))] 21 | sch_e = [simpy.Event(orc.env.sim) for _ in range(len(EDGE_NAMES))] 22 | dep_e = [simpy.Event(orc.env.sim) for _ in range(len(EDGE_NAMES))] 23 | pro_e = [simpy.Event(orc.env.sim) for _ in range(len(EDGE_NAMES))] 24 | 25 | offload, schedule, deploy, process = orc.get_decision_from_model() 26 | 27 | print(f"offload = {offload}") 28 | print(f"schedule = {schedule}") 29 | print(f"deploy = {deploy}") 30 | print(f"deploy = {process}") 31 | 32 | for j, edge_name in enumerate(EDGE_NAMES): 33 | orc.env.sim.process(orc.offload_all_device_to_edge(offload[edge_name], edge_name, offload_e=off_e[j])) 34 | orc.env.sim.process(orc.schedule_all_task_to_other(edge_name, schedule[edge_name], offload_e=off_e[j], schedule_e=sch_e[j])) 35 | orc.env.sim.process(orc.execute_deploy_decision_on_edge(edge_name, deploy[edge_name], schedule_e=sch_e[j], deploy_e=dep_e[j])) 36 | orc.env.sim.process(orc.process_all_tasks_on_edge(edge_name, process[edge_name], deploy_e=dep_e[j], process_e=pro_e[j])) 37 | 38 | orc.t += 10 39 | orc.env.sim.run(until=orc.t) 40 | 41 | task_processed_info = { 42 | edge_name: orc.scenario.get_edge(edge_name).done_task_info 43 | for edge_name in EDGE_NAMES 44 | } 45 | 46 | simulation_data = {edge_name: [] for edge_name in EDGE_NAMES} 47 | for edge_name in EDGE_NAMES: 48 | for info in task_processed_info[edge_name]: 49 | simulation_data[edge_name].append(info["cost_time"]) 50 | 51 | # print(orc.get_edge_deployed_info_for_model()) 52 | save_data_to_excel(simulation_data) 53 | 54 | 55 | def save_data_to_excel(data): 56 | current_time = datetime.now() 57 | formatted_time = current_time.strftime("%d_%H-%M-%S") 58 | file_name = f"data_without_schedule_{formatted_time}.xlsx" 59 | xls_path = f"./output/{file_name}" 60 | excel_writer = pd.ExcelWriter(xls_path) 61 | 62 | max_length = max([len(lis) for key, lis in data.items()]) 63 | for key, lis in data.items(): 64 | data[key] = lis + [None] * (max_length - len(lis)) 65 | 66 | data_pd = pd.DataFrame(data) 67 | data_pd.to_excel(excel_writer, index=True) 68 | 69 | excel_writer.close() 70 | 71 | 72 | if __name__ == '__main__': 73 | main() 74 | --------------------------------------------------------------------------------