drake  1.0.0
src/mapping.c
Go to the documentation of this file.
00001 /*
00002  Copyright 2015 Nicolas Melot
00003 
00004  This file is part of Drake.
00005 
00006  Drake is free software: you can redistribute it and/or modify
00007  it under the terms of the GNU General Public License as published by
00008  the Free Software Foundation, either version 3 of the License, or
00009  (at your option) any later version.
00010 
00011  Drake is distributed in the hope that it will be useful,
00012  but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
00014  GNU General Public License for more details.
00015 
00016  You should have received a copy of the GNU General Public License
00017  along with Drake. If not, see <http://www.gnu.org/licenses/>.
00018 
00019 */
00020 
00021 
00022 
00023 
00024 #include <stdlib.h>
00025 #include <string.h>
00026 
00027 #include <drake/mapping.h>
00028 #include <drake/platform.h>
00029 #include <assert.h>
00030 
00031 #include "drawgraph-2.h"
00032 
00033 // Mapping manipulations
00034 mapping_t*
00035 pelib_alloc_collection(mapping_t)(size_t size)
00036 {
00037   mapping_t * mapping;
00038   size_t res;
00039 
00040   res = 1;
00041   mapping = malloc(sizeof(mapping_t) + sizeof(processor_t*) * size);
00042 
00043   if (mapping != NULL)
00044     {
00045       mapping->proc = malloc(sizeof(processor_t*) * size);
00046       if(mapping->proc != NULL)
00047       {
00048       mapping->processor_count = 0;
00049       mapping->max_processor_count = size;
00050       mapping->task_count = 0;
00051 
00052       // Makes sure the allocated memory was actually allocated
00053       if (res != 0)
00054         {
00055           return mapping;
00056         }
00057       }
00058       free(mapping->proc);
00059       free(mapping);
00060     }
00061 
00062   return NULL;
00063 }
00064 
00065 int
00066 pelib_free(mapping_t)(mapping_t * solution)
00067 {
00068   size_t i;
00069 
00070   for (i = 0; i < solution->processor_count; i++)
00071     {
00072       pelib_free(processor_t)(solution->proc[i]);
00073     }
00074   free(solution->proc);
00075   free(solution);
00076 
00077   return 1;
00078 }
00079 
00080 int
00081 pelib_copy(mapping_t)(mapping_t source, mapping_t *copy)
00082 {
00083   size_t i;
00084 
00085   //copy = pelib_alloc(mapping_t)(DRAKE_MAPPING_MAX_TASK_COUNT);
00086   copy->processor_count = source.processor_count;
00087   copy->task_count = source.task_count;
00088 
00089   for (i = 0; i < copy->processor_count; i++)
00090     {
00091       //drake_processor_destroy(copy->proc[i]);
00092       pelib_copy(processor_t)(*source.proc[i], copy->proc[i]);
00093     }
00094 
00095   return 1;
00096 }
00097 
00098 int
00099 drake_mapping_insert_task(mapping_t* mapping, processor_id pid, task_t* task)
00100 {
00101   int processor_index;
00102 
00103   processor_index = drake_mapping_find_processor_index(mapping, pid);
00104   
00105   if (drake_processor_insert_task(mapping->proc[processor_index], task) == 1)
00106     {
00107       mapping->task_count++;
00108 
00109       return 1;
00110     }
00111   else
00112     {
00113       return 0;
00114     }
00115 }
00116 int
00117 drake_mapping_remove_task(mapping_t* mapping, task_id task)
00118 {
00119   processor_id pid;
00120 
00121   pid = drake_mapping_find_processor(mapping, task);
00122 
00123   if (pid < mapping->processor_count && drake_processor_remove_task(
00124       mapping->proc[pid], task) == 1)
00125     {
00126       mapping->task_count--;
00127 
00128       return 1;
00129     }
00130   else
00131     {
00132       return 0;
00133     }
00134 }
00135 int
00136 drake_mapping_find_processor_index(mapping_t* mapping, processor_id pid)
00137 {
00138   int i;
00139   for (i = 0; i < mapping->processor_count; i++)
00140     {
00141       if (mapping->proc[i]->id == pid)
00142         {
00143           return i;
00144         }
00145     }
00146   return i;
00147 }
00148 processor_id
00149 drake_mapping_find_processor(mapping_t* mapping, task_id tid)
00150 {
00151   int i;
00152   for (i = 0; i < mapping->processor_count; i++)
00153     {
00154       if (drake_processor_find_task(mapping->proc[i], tid)
00155           != mapping->proc[i]->handled_nodes)
00156         {
00157           return mapping->proc[i]->id;
00158         }
00159     }
00160 
00161   return -1;
00162 }
00163 int
00164 drake_mapping_insert_processor(mapping_t* mapping, processor_t* processor)
00165 {
00166   // If there is room for a new processor in mapping, and this processor id was not already present
00167   if (mapping->processor_count < mapping->max_processor_count
00168       && drake_mapping_find_processor_index(mapping, processor->id)
00169           == mapping->processor_count)
00170     {
00171         mapping->proc[mapping->processor_count] = pelib_alloc_collection(processor_t)(processor->node_capacity);
00172 
00173 //      printf("%s: %X\n", __FUNCTION__, mapping->proc[mapping->processor_count]);
00174 
00175       if (mapping->proc[mapping->processor_count] != NULL)
00176         {
00177       pelib_copy(processor_t)(*processor, mapping->proc[mapping->processor_count]);
00178           mapping->processor_count++;
00179 
00180           return 1;
00181         }
00182       else
00183         {
00184           return 0;
00185         }
00186     }
00187   else
00188     {
00189       return 0;
00190     }
00191 }
00192 int
00193 drake_mapping_remove_processor(mapping_t* mapping, int processor_id)
00194 {
00195   // TODO: implement
00196   return 0;
00197 }
00198 
00199 // Mapping properties
00200 int
00201 drake_mapping_violations(mapping_t* mapping)
00202 {
00203   // A mapping is correct iff every task is mapped to exactly one processor
00204   processor_id pid, found_pid;
00205   size_t i, mapped, overmapped;
00206 
00207   overmapped = 0;
00208   mapped = 0;
00209 
00210   for (pid = 0; pid < mapping->processor_count; pid++)
00211     {
00212       for (i = 0; i < mapping->proc[pid]->handled_nodes; i++)
00213         {
00214           found_pid = drake_mapping_find_processor(mapping,
00215               mapping->proc[pid]->task[i]->id);
00216 
00217           if (found_pid == pid) // All good
00218             {
00219               mapped++;
00220             }
00221           else
00222             {
00223               if (found_pid != mapping->processor_count) // // The task is mapped to several processors
00224                 {
00225                   overmapped++;
00226                 }
00227               // else the task is not mapped at all
00228             }
00229         }
00230     }
00231 
00232   if (mapped == mapping->task_count && overmapped == 0)
00233     {
00234       return 1;
00235     }
00236   else
00237     {
00238       return 0;
00239     }
00240 }
00241 
00242 // Mapping human interface
00243 FILE*
00244 pelib_printf(mapping_t)(FILE* stream, mapping_t mapping)
00245 {
00246   char *str = pelib_string(mapping_t)(mapping);
00247   fprintf(stream, "%s\n", str);
00248 
00249   free(str);
00250 
00251   return stream;
00252 }
00253 
00254 char*
00255 pelib_string(mapping_t)(mapping_t mapping)
00256 {
00257   size_t i, total_length;
00258   char *proc_str, *str;
00259 
00260   total_length = 0;
00261   for (i = 0; i < mapping.processor_count; i++)
00262     {
00263       total_length += (DRAKE_MAPPING_PROC_ID_CHAR_LENGTH
00264           + (sizeof(DRAKE_MAPPING_SEPARATOR) + DRAKE_MAPPING_NODE_CHAR_LENGTH)
00265               * mapping.proc[i]->handled_nodes + 2);
00266     }
00267   total_length++; // Provide space for the trailing character \0
00268 
00269   str = malloc(sizeof(char) * total_length);
00270   str[0] = '\0';
00271 
00272   for (i = 0; i < mapping.processor_count; i++)
00273     {
00274       proc_str = pelib_string(processor_t)(*mapping.proc[i]);
00275       sprintf(&(str[strlen(str)]), "[%s]", proc_str);
00276       free(proc_str);
00277     }
00278 
00279   return str;
00280 }
00281 
00282 static int
00283 take_all_tasks(task_t *task)
00284 {
00285   return 1;
00286 }
00287 
00288 static mapping_t*
00289 mapping_loadstr(mapping_t * mapping, char * str, int(filter)(task_t*))
00290 {
00291   FILE * stream_str;
00292 
00293   //printf("[%s] %s\n", __func__, str);
00294   stream_str = (FILE*)fmemopen((void*)str, strlen(str), "r");
00295  // printf("file descriptor: %i\n", *stream_str);
00296 
00297   mapping = drake_mapping_loadfilterfile(mapping, stream_str, filter);
00298   fclose(stream_str);
00299   //printf("%i\n", i == EOF);
00300 
00301   return mapping;
00302 }
00303 
00304 mapping_t*
00305 drake_mapping_loadstr(mapping_t * mapping, char * str)
00306 {
00307   return mapping_loadstr(mapping, str, take_all_tasks);
00308 }
00309 
00310 mapping_t*
00311 drake_mapping_loadfilterstr(mapping_t* mapping, char* str, int (filter)(task_t*))
00312 {
00313   //printf("[%s] %s\n", __func__, str);
00314   return mapping_loadstr(mapping, str, filter);
00315 }
00316 
00317 /* TODO: draw mappings with as many tasks as in the mapping instead of 2 ^ (p - 1) */
00318 static void
00319 mapping_draw(FILE* read, FILE* write, FILE* err)
00320 {
00321   pelib_drawgraph2_draw(read, write, err);
00322 }
00323 
00324 mapping_t*
00325 drake_mapping_loadfile(mapping_t * mapping, FILE * file)
00326 {
00327   return drake_mapping_loadfilterfile(mapping, file, take_all_tasks);
00328 }
00329 
00330 mapping_t*
00331 drake_mapping_loadfilterfile(mapping_t * mapping, FILE * file, int (filter)(task_t*))
00332 {
00333 /*  char line [ 128 ];
00334   printf("[%s] ", __func__);
00335         while ( fgets ( line, sizeof line, file ) != NULL )
00336         {
00337            fputs ( line, stdout );
00338         }
00339         //fclose ( file );
00340         return NULL;*/
00341   mapping = pelib_drawgraph2_load(file, mapping, filter);
00342   //printf("[%s] ", __func__);
00343   //drake_mapping_display(mapping);
00344   return mapping;
00345 }
00346 
00347 char*
00348 drake_mapping_drawstr(mapping_t * mapping, char * str)
00349 {
00350   unsigned int i, k, proc_index, task_index;
00351   size_t length;
00352   FILE *stream;
00353 
00354   // Opens a stream that points to str
00355   stream = (FILE*)open_memstream(&str, &length);
00356   assert(stream != NULL);
00357 
00358   // Warm-up
00359   fprintf(stream, "k = %u\n", mapping->processor_count);
00360   fprintf(stream, DRAKE_MAPPING_OUT_WARMUP);
00361   fprintf(stream, "%-*c", DRAKE_MAPPING_OUT_NODE_COLUMN_WIDTH, ':');
00362   for (i = 0; i < mapping->processor_count; i++)
00363     {
00364       fprintf(stream, "%-*u", DRAKE_MAPPING_OUT_PROC_COLUMN_WIDTH, i + 1);
00365     }
00366   fprintf(stream, "%s\n", DRAKE_MAPPING_OUT_AFFECT);
00367 
00368   for (task_index = 0; task_index < mapping->task_count; task_index++)
00369     {
00370       proc_index = drake_mapping_find_processor_index(mapping, drake_mapping_find_processor(mapping, task_index + 1));
00371       fprintf(stream, "%-*u", DRAKE_MAPPING_OUT_NODE_COLUMN_WIDTH, task_index + 1);
00372 
00373       for (k = 0; k < mapping->processor_count; k++)
00374         {
00375           if (k != proc_index)
00376             {
00377               fprintf(stream, "%-*u", DRAKE_MAPPING_OUT_PROC_COLUMN_WIDTH, 0);
00378             }
00379           else
00380             {
00381               fprintf(stream, "%-*u", DRAKE_MAPPING_OUT_PROC_COLUMN_WIDTH, 1);
00382             }
00383         }
00384       fprintf(stream, "\n");
00385     }
00386   fprintf(stream, DRAKE_MAPPING_OUT_ENDING);
00387 
00388   // Closes the stream
00389   fflush(stream);
00390   fclose(stream);
00391 
00392   return str;
00393 }
00394 
00395 task_t*
00396 drake_mapping_find_task(mapping_t* mapping, task_id id)
00397 {
00398         int target_task_rank, target_proc_rank;
00399         processor_t *target_proc;
00400 
00401         target_proc_rank = drake_mapping_find_processor(mapping, id);
00402         if(target_proc_rank >= 0)
00403         {
00404                 target_proc = mapping->proc[target_proc_rank];
00405                 target_task_rank = drake_processor_find_task(target_proc, id);
00406 
00407                 if(target_task_rank >= 0)
00408                 {
00409                         return target_proc->task[target_task_rank];
00410                 }
00411         }
00412         
00413         return NULL;
00414 }
00415 
00416 int
00417 drake_mapping_draw(mapping_t * mapping, FILE * file)
00418 {
00419   char * str = NULL;
00420   FILE *stream;
00421 
00422   str = drake_mapping_drawstr(mapping, str);
00423   stream = (FILE*)fmemopen(str, strlen(str) + 1, "r");
00424 
00425   mapping_draw(stream, file, stderr);
00426   fclose(stream);
00427 
00428   free(str);
00429 
00430   return 1;
00431 }
00432