Skip to content
Snippets Groups Projects
algo.c 11.95 KiB
#include "algo.h"

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <string.h>
#include <limits.h>

#include "util.h"
#include "list.h"
#include "tree.h"
#include "instance.h"
#include "schedule.h"

/********************************************************************
 * event_key_t
 ********************************************************************/

/**
 * @brief 
 * Une structure qui definit la clé de l'ensemble des événements.
 */
struct event_key_t {
	int event_type; // 0 si l'événement correspond à la libération d'une tâche,
					// 1 si l'événement correspond à la fin d'exécution d'une tâche
	unsigned long event_time;
	unsigned long processing_time; // par convention, 0 si l'événement correspond à la fin d'exécution d'une tâche
								   // sinon, la durée opératoire de la tâche qui va être libérée
	char * task_id;
	int machine; // par convention, 0 si l'événement correspond à la libération d'une tâche,
				 // sinon, la machine qui exécute la tâche de l'événement
};

/**
 * @brief 
 * Une énumération qui définit le type d'évènement
 */
enum even_type_e {
	EVT_LIBERATION = 0,
	EVT_FIN_EXEC,
};

/**
 * @brief 
 * 
 * @param[in] event_type 
 * @param[in] event_time 
 * @param[in] processing_time 
 * @param[in] task_id 
 * @param[in] machine 
 * @return struct event_key_t* 
 */
struct event_key_t * new_event_key(int event_type, unsigned long event_time, unsigned long processing_time, char * task_id, int machine) {
	struct event_key_t * key = malloc(sizeof(struct event_key_t));
	key->event_type = event_type;
	key->event_time = event_time;
	key->processing_time = processing_time;
	key->task_id = strdup(task_id);
	key->machine = machine;
	return key;
}

/**
 * @brief 
 * 
 * @param[in] key 
 * @return int 
 */
int get_event_type(const struct event_key_t * key) {
	assert(key);
	return key->event_type;
}

/**
 * @brief 
 * 
 * @param[in] key 
 * @return unsigned long 
 */
unsigned long get_event_time(const struct event_key_t * key) {
	assert(key);
	return key->event_time;
}

/**
 * @brief 
 * 
 * @param[in] key 
 * @return unsigned long 
 */
unsigned long get_event_processing_time(const struct event_key_t * key) {
	assert(key);
	return key->processing_time;
}

/**
 * @brief 
 * 
 * @param[in] key 
 * @return char* 
 */
char * get_event_task_id(const struct event_key_t * key) {
	assert(key);
	return key->task_id;
}

/**
 * @brief 
 * 
 * @param[in] key 
 * @return int 
 */
int get_event_machine(const struct event_key_t * key) {
	assert(key);
	return key->machine;
}

/**
 * @brief 
 * 
 * @param[in] key 
 */
void view_event_key(const void * key) {
	// A FAIRE
	const struct event_key_t* ekey = (const struct event_key_t *) key;
	printf("event type: %d,  event time: %lu, processing time: %lu, task id: %s, machine: %d\n", 
	ekey->event_type, ekey->event_time, ekey->processing_time, ekey->task_id, ekey->machine);
}

/**
 * @brief 
 * 
 * @param[in] key 
 */
void delete_event_key(void * key) {
	struct event_key_t* ekey = (struct event_key_t *) key;
	free(ekey->task_id);
	free(ekey);
}
/**
 * @brief Comparer deux événements \p a et \p b.
 * Les règles de comparaison sont données dans la présentation du cours.
 * 
 * @param[in] a 
 * @param[in] b 
 * @return int 
 */
int event_preceed(const void * a, const void * b) {
	// A FAIRE
	const struct event_key_t* Akey = (const struct event_key_t *) a;
	const struct event_key_t* Bkey = (const struct event_key_t *) b;
	if(Akey->event_time < Bkey->event_time) {
		return 1;
	}
	else{ //tj = tk
		//typej =  arrivee  et typek = fin d execution 
		if(get_event_type(Akey) == EVT_LIBERATION && get_event_type(Bkey) == EVT_FIN_EXEC ){
			return 1;
		} else if ((get_event_type(Akey) + get_event_type(Bkey)) == EVT_LIBERATION)
		{
			//typej = typek = arrivee et pj = pk et j < k
			if(get_event_processing_time(Akey) == get_event_processing_time(Bkey) 
			&& strcmp(get_event_task_id(Akey), get_event_task_id(Bkey)) < 0){
				return 1;
			}
			//typej = typek = arrivee et pj < pk
			else if(get_event_processing_time(Akey) < get_event_processing_time(Bkey)){
				return 1;
			}
		}
		//typej = typek =  fin d execution et mj < mk
		else if((get_event_type(Akey) & get_event_type(Bkey) == EVT_FIN_EXEC) && get_event_machine(Akey) < get_event_machine(Bkey)){
			return 1;
		}
	}
	return 0;	
}

/********************************************************************
 * ready_task_key_t
 ********************************************************************/

/**
 * @brief
 * Une structure qui définit la clé de la file d'attente avec les "ready tasks".
 */
struct ready_task_key_t {
	unsigned long remaining_processing_time;
	char * task_id;
};

/**
 * @brief 
 * 
 * @param[in] remaining_processing_time 
 * @param[in] task_id 
 * @return struct ready_task_key_t* 
 */
struct ready_task_key_t * new_ready_task_key(unsigned long remaining_processing_time, char * task_id) {
	// A FAIRE
	struct ready_task_key_t *key = malloc(sizeof(struct ready_task_key_t));
    key->remaining_processing_time = remaining_processing_time;
    key->task_id = strdup(task_id);
    return key;
}

/**
 * @brief 
 * 
 * @param[in] key 
 * @return unsigned long 
 */
unsigned long get_ready_task_remaining_processing_time(const struct ready_task_key_t * key) {
	// A FAIRE
	assert(key);
	return key->remaining_processing_time;
}

/**
 * @brief 
 * 
 * @param[in] key 
 * @return char* 
 */
char * get_ready_task_id(const struct ready_task_key_t * key) {
	// A FAIRE
	assert(key);
	return key->task_id;
}

/**
 * @brief 
 * 
 * @param[in] key 
 */
void view_ready_task_key(const void * key) {
	// A FAIRE
	const struct ready_task_key_t *ready_key = (const struct ready_task_key_t *) key;
    printf(" remaining processing time: %lu |  task id: %s\n", ready_key->remaining_processing_time, ready_key->task_id);
}

/**
 * @brief 
 * 
 * @param[in] key 
 */
void delete_ready_task_key(void * key) {
	// A FAIRE
	struct ready_task_key_t *ready_key = (struct ready_task_key_t *) key;
    free(ready_key->task_id);
    free(ready_key);
}
/**
 * @brief Comparer deux tâches \p a et \p b de la file d'attente afin de définir la tâche la plus prioritaire.
 * Les deux paramètres d'entrée \p a et \p b sont de type struct ready_task_key_t *.
 * Les règles de comparaison sont données dans la présentation du cours.
 *
 * @param[in] a 
 * @param[in] b 
 * @return int 
 */
int ready_task_preceed(const void * a, const void * b) {
	// A FAIRE
	struct ready_task_key_t* ta = a;
	struct ready_task_key_t* tb = b;
	int res = get_ready_task_remaining_processing_time(b) - get_ready_task_remaining_processing_time(a);
	if (res == 0)
		return strcmp(get_ready_task_id(ta), get_ready_task_id(tb)) < 0;
	else
		return res > 0;
}
//note: peut etre utiliser strcmp pour comparer les chars ?

/********************************************************************
 * The algorithm
 ********************************************************************/

struct schedule_t * create_schedule(Instance I, int num_m, int preemption, int balanced_tree) {
	// A FINIR !
	//initialisation
	struct schedule_t* ordonnancement = new_schedule(num_m);
	struct tree_t* ready_tasks = new_tree(balanced_tree, ready_task_preceed, view_ready_task_key, view_task, delete_ready_task_key, delete_task);
	struct tree_t* event_tree = new_tree(balanced_tree, event_preceed, view_event_key, view_task, delete_event_key, delete_task);
	
	//parcourir l'instance
	struct list_node_t* node = get_list_head(I);
	while(node != NULL){
		struct task_t* task = (struct task_t*) get_list_node_data(node);
		struct event_key_t* key = new_event_key(EVT_LIBERATION, 
			get_task_release_time(task), get_task_processing_time(task), get_task_id(task), 0);
		tree_insert(event_tree, key, task);
		
		node = get_successor(node);
	}



	while(get_tree_size(event_tree) != 0){
		//Extraire de E l’ ́evenement e correspondant a l’instant t le plus petit
		//a verfieier ?
		struct tree_node_t* event_node = tree_min(get_root(event_tree));  // recuperation du node a l instant t le plus petit
		struct event_key_t* event_key = (struct event_key_t*) get_tree_node_key(event_node);
		struct task_t* task = (struct task_t*) get_tree_node_data(event_node); //recuperer la data et la cast en tache
		
		// Si e concerne la libération d'une tache Tj
		if (get_event_type(event_key) == EVT_LIBERATION) {
			int machine = find_empty_machine(ordonnancement, get_event_time(event_key));
			//si il existe une machine Mi libre en t alors
			if (machine != -1) {
				//Affecter Tj a Mi en t dans S
				add_task_to_schedule(ordonnancement, task, machine, get_event_time(event_key), get_event_time(event_key) + get_event_processing_time(event_key));
				//Ajouter dans E l’ evenement fin d’execution de la tache Tj
				struct event_key_t* end_key = new_event_key(EVT_FIN_EXEC, get_event_time(event_key) + get_event_processing_time(event_key), get_event_processing_time(event_key), get_task_id(task), machine);
				tree_insert(event_tree, end_key, task);
			}
			else if (preemption)
			{
				int end_time = (get_event_time(event_key) + get_event_processing_time(event_key));

				int machine_inter = find_machine_to_interrupt(ordonnancement, get_event_time(event_key), get_event_processing_time(event_key));
				if (machine_inter != -1) {
					// Verif preemption de tache
					struct task_t* caninterrupt = NULL;
					struct list_node_t* walk = get_list_head(get_schedule_of_machine(ordonnancement, machine_inter));
					while (walk) {
						struct schedule_node_t* taskholder = get_list_node_data(walk);
						if (get_schedule_node_end_time(taskholder) > end_time) {
							caninterrupt = get_schedule_node_task(taskholder);
							break;
						}
						walk = get_successor(walk);
					}
					// On peut preempter la tache et remplacer l'evenement de fin de tâche
					if (caninterrupt) {
						int timediff = preempt_task(ordonnancement, machine_inter, end_time);

						tree_remove(event_tree, get_task_id(caninterrupt));
						struct ready_task_key_t* interkey = new_ready_task_key(timediff, get_task_id(caninterrupt));
						tree_insert(ready_tasks, interkey, caninterrupt);

						add_task_to_schedule(ordonnancement, task, machine_inter, get_event_time(event_key), get_event_time(event_key) + get_event_processing_time(event_key));
						struct event_key_t* end_key = new_event_key(EVT_FIN_EXEC, get_event_time(event_key) + get_event_processing_time(event_key), get_event_processing_time(event_key), get_task_id(task), machine_inter);
						tree_insert(event_tree, end_key, task);
					}
				}
			}
			else {
				//Ajouter Tj dans la file d’attente Q
				tree_insert(ready_tasks, event_key, task);
			}
		}
		else if(get_event_type(event_key) == EVT_FIN_EXEC) { //sinon si e concerne la fin d’execution d’une tache Tj sur Mi alors

			if(get_tree_size(ready_tasks) != 0){ ////si la file d’attente Q n’est pas vide
				//Extraire de Q la tache Tk avec la duree la plus courte (regle SPT)
				struct tree_node_t* shortest_node = tree_min(get_root(ready_tasks)); //pareil qu'en haut, a verifier
				struct ready_task_key_t* shortest_task_key = (struct ready_task_key_t*) get_tree_node_key(shortest_node);
                struct task_t* shortest_task = (struct task_t*) get_tree_node_data(shortest_node);

				//Affecter Tk a Mi en t dans S
				int machine = find_empty_machine(ordonnancement, get_event_time(event_key));
				add_task_to_schedule(ordonnancement, shortest_task, machine, get_event_time(event_key), get_event_time(event_key) + get_event_processing_time(event_key));

				//Ajouter dans E l’ ́evenement fin d’execution de la tache
				struct event_key_t* end_key = new_event_key(EVT_FIN_EXEC, get_event_time(event_key) + get_event_processing_time(event_key), get_event_processing_time(event_key), get_task_id(task), machine);
				tree_insert(event_tree, end_key, shortest_task);

				if(get_tree_size(ready_tasks) != 0){
                	tree_remove(ready_tasks, shortest_task_key);
				}
            }


		}
		tree_remove(event_tree, event_key);
		
	}

	//fin de la fonction, libreation mem des arbres
	delete_tree(event_tree, delete_event_key, NULL);
	delete_tree(ready_tasks, delete_ready_task_key, NULL);
	return ordonnancement;
}