├── .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 |
4 |
5 |
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 |
--------------------------------------------------------------------------------