@@ -75,9 +75,13 @@ def __init__(self, name: str,
7575 self .input_file_size_factor = input_file_size_factor
7676 self .output_file_size_factor = output_file_size_factor
7777 self .workflows : List [Workflow ] = []
78+ self .tasks_map = {}
7879 self .tasks_files : Dict [str , List [File ]] = {}
80+ self .tasks_files_names : Dict [str , List [str ]] = {}
7981 self .task_id_counter = 1
8082 self .this_dir = this_dir
83+ self .tasks_children = {}
84+ self .tasks_parents = {}
8185
8286 @abstractmethod
8387 def _workflow_recipe (self ) -> Dict [str , Any ]:
@@ -142,7 +146,8 @@ def build_workflow(self, workflow_name: Optional[str] = None) -> Workflow:
142146 :return: A synthetic workflow instance object.
143147 :rtype: Workflow
144148 """
145- workflow = Workflow (name = self .name + "-synthetic-instance" if not workflow_name else workflow_name , makespan = None )
149+ workflow = Workflow (name = self .name + "-synthetic-instance" if not workflow_name else workflow_name ,
150+ makespan = 0 )
146151 graph = self .generate_nx_graph ()
147152
148153 task_names = {}
@@ -156,11 +161,30 @@ def build_workflow(self, workflow_name: Optional[str] = None) -> Workflow:
156161
157162 task_names [node ] = task_name
158163
164+ # tasks dependencies
159165 for (src , dst ) in graph .edges :
160166 if src in ["SRC" , "DST" ] or dst in ["SRC" , "DST" ]:
161167 continue
162168 workflow .add_edge (task_names [src ], task_names [dst ])
163169
170+ if task_names [src ] not in self .tasks_children :
171+ self .tasks_children [task_names [src ]] = []
172+ if task_names [dst ] not in self .tasks_parents :
173+ self .tasks_parents [task_names [dst ]] = []
174+
175+ self .tasks_children [task_names [src ]].append (task_names [dst ])
176+ self .tasks_parents [task_names [dst ]].append (task_names [src ])
177+
178+ # find leaf tasks
179+ leaf_tasks = []
180+ for node_name in workflow .nodes :
181+ task : Task = workflow .nodes [node_name ]['task' ]
182+ if task .name not in self .tasks_children :
183+ leaf_tasks .append (task )
184+
185+ for task in leaf_tasks :
186+ self ._generate_task_files (task )
187+
164188 workflow .nxgraph = graph
165189 self .workflows .append (workflow )
166190 return workflow
@@ -171,21 +195,13 @@ def _load_base_graph(self) -> nx.DiGraph:
171195 def _load_microstructures (self ) -> Dict :
172196 return json .loads (self .this_dir .joinpath ("microstructures.json" ).read_text ())
173197
174- def _generate_task (self , task_name : str ,
175- task_id : str ,
176- input_files : Optional [List [File ]] = None ,
177- files_recipe : Optional [Dict [FileLink , Dict [str , int ]]] = None
178- ) -> Task :
198+ def _generate_task (self , task_name : str , task_id : str ) -> Task :
179199 """Generate a synthetic task.
180200
181201 :param task_name: task name.
182202 :type task_name: str
183203 :param task_id: task ID.
184204 :type task_id: str
185- :param input_files: List of input files to be included.
186- :type input_files: List[File]
187- :param files_recipe: Recipe for generating task files.
188- :type files_recipe: Dict[FileLink, Dict[str, int]]
189205
190206 :return: A task object.
191207 :rtype: task
@@ -197,22 +213,17 @@ def _generate_task(self, task_name: str,
197213 task_recipe ['runtime' ]['min' ],
198214 task_recipe ['runtime' ]['max' ]), '.3f' ))
199215
200- # linking previous generated output files as input files
216+ # # linking previous generated output files as input files
201217 self .tasks_files [task_id ] = []
202- if input_files :
203- for f in input_files :
204- if f .link == FileLink .OUTPUT :
205- self .tasks_files [task_id ].append (File (name = f .name , size = f .size , link = FileLink .INPUT ))
206-
207- # generate additional in/output files
208- self ._generate_files (task_id , task_recipe ['input' ], FileLink .INPUT , files_recipe )
209- self ._generate_files (task_id , task_recipe ['output' ], FileLink .OUTPUT , files_recipe )
210-
211- return Task (
218+ self .tasks_files_names [task_id ] = []
219+ task = Task (
212220 name = task_id ,
221+ task_id = '0{}' .format (task_id .split ('_0' )[1 ]),
222+ category = task_name ,
213223 task_type = TaskType .COMPUTE ,
214224 runtime = runtime ,
215225 machine = None ,
226+ program = task_name ,
216227 args = [],
217228 cores = 1 ,
218229 avg_cpu = None ,
@@ -222,8 +233,11 @@ def _generate_task(self, task_name: str,
222233 energy = None ,
223234 avg_power = None ,
224235 priority = None ,
225- files = self . tasks_files [ task_id ]
236+ files = [ ]
226237 )
238+ self .tasks_map [task_id ] = task
239+
240+ return task
227241
228242 def _generate_task_name (self , prefix : str ) -> str :
229243 """Generate a task name from a prefix appended with an ID.
@@ -238,8 +252,40 @@ def _generate_task_name(self, prefix: str) -> str:
238252 self .task_id_counter += 1
239253 return task_name
240254
241- def _generate_files (self , task_id : str , recipe : Dict [str , Any ], link : FileLink ,
242- files_recipe : Optional [Dict [FileLink , Dict [str , int ]]] = None ) -> None :
255+ def _generate_task_files (self , task : Task ) -> List [File ]:
256+ """Generate input and output files for a task.
257+
258+ :param task: task object.
259+ :type task: Task
260+
261+ :return: List of files output files.
262+ :rtype: List[File]
263+ """
264+ task_recipe = self ._workflow_recipe ()[task .category ]
265+
266+ # generate output files
267+ output_files_list = self ._generate_files (task .name , task_recipe ['output' ], FileLink .OUTPUT )
268+ task .files = self .tasks_files [task .name ]
269+
270+ # obtain input files from parents
271+ input_files = []
272+ if task .name in self .tasks_parents .keys ():
273+ for parent_task_name in self .tasks_parents [task .name ]:
274+ input_files .extend (self ._generate_task_files (self .tasks_map [parent_task_name ]))
275+
276+ for input_file in input_files :
277+ if input_file .name not in self .tasks_files_names [task .name ]:
278+ self .tasks_files [task .name ].append (File (name = input_file .name ,
279+ link = FileLink .INPUT ,
280+ size = input_file .size ))
281+ self .tasks_files_names [task .name ].append (input_file .name )
282+
283+ # generate additional input files
284+ self ._generate_files (task .name , task_recipe ['input' ], FileLink .INPUT )
285+
286+ return output_files_list
287+
288+ def _generate_files (self , task_id : str , recipe : Dict [str , Any ], link : FileLink ) -> List [File ]:
243289 """Generate files for a specific task ID.
244290
245291 :param task_id: task ID.
@@ -248,21 +294,27 @@ def _generate_files(self, task_id: str, recipe: Dict[str, Any], link: FileLink,
248294 :type recipe: Dict[str, Any]
249295 :param link: Type of file link.
250296 :type link: FileLink
251- :param files_recipe: Recipe for generating task files.
252- :type files_recipe: Dict[FileLink, Dict[str, int]]
297+
298+ :return: List of files.
299+ :rtype: List[File]
253300 """
301+ files_list = []
254302 extension_list : List [str ] = []
255303 for f in self .tasks_files [task_id ]:
256304 if f .link == link :
305+ files_list .append (f )
257306 extension_list .append (path .splitext (f .name )[1 ] if '.' in f .name else f .name )
258307
259308 for extension in recipe :
260309 if extension not in extension_list :
261310 num_files = 1
262- if files_recipe and link in files_recipe and extension in files_recipe [link ]:
263- num_files = files_recipe [link ][extension ]
264311 for _ in range (0 , num_files ):
265- self .tasks_files [task_id ].append (self ._generate_file (extension , recipe , link ))
312+ file = self ._generate_file (extension , recipe , link )
313+ files_list .append (file )
314+ self .tasks_files [task_id ].append (file )
315+ self .tasks_files_names [task_id ].append (file .name )
316+
317+ return files_list
266318
267319 def _generate_file (self , extension : str , recipe : Dict [str , Any ], link : FileLink ) -> File :
268320 """Generate a file according to a file recipe.
0 commit comments