pelib  2.0.0
src/Task.cpp
Go to the documentation of this file.
00001 /*
00002  Copyright 2015 Nicolas Melot
00003 
00004  This file is part of Pelib.
00005 
00006  Pelib 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  Pelib 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 Pelib. If not, see <http://www.gnu.org/licenses/>.
00018 */
00019 
00020 
00021 #include <iostream>
00022 #include <sstream>
00023 #include <string>
00024 
00025 #include <pelib/pelib_exprtk.hpp>
00026 
00027 #include <pelib/Task.hpp>
00028 #include <pelib/ParseException.hpp>
00029 
00030 #ifdef debug
00031 #undef debug
00032 #endif
00033 
00034 #define debug(expr) cout << "[" << __FILE__ << ":" << __FUNCTION__ << ":" << __LINE__ << "] " << #expr << " = \"" << (expr) << "\"." << endl;
00035 
00036 using namespace std;
00037 
00038 namespace pelib
00039 {
00040         const float Task::very_small = 1e-6;
00041 
00042         Task::Task(const std::string &name, bool is_streaming)
00043         {
00044                 this->name = name;
00045                 this->module = "dummy";
00046                 this->frequency = 1;
00047                 this->width = 1;
00048                 this->maxWidth = 1;
00049                 this->workload = 1;
00050                 this->streaming = is_streaming;
00051                 this->efficiencyString = "exprtk:p <= 1 ? 1 : 1e-6";
00052                 this->start_time = 0;
00053         }
00054 
00055         Task::Task(const Task &task)
00056         {
00057                 this->name = task.getName();
00058                 this->module = task.getModule();
00059                 this->frequency = task.getFrequency();
00060                 this->width = task.getWidth();
00061                 this->maxWidth = task.getMaxWidth();
00062                 this->workload = task.getWorkload();
00063                 this->streaming = task.isStreaming();
00064                 this->efficiencyString = task.getEfficiencyString();
00065                 this->start_time = task.getStartTime();
00066 
00067                 this->consumers = task.getConsumers();
00068                 this->producers = task.getProducers();
00069         }
00070 
00071         Task::~Task()
00072         {
00073                 /* Do nothing */
00074         }
00075         
00076         double
00077         Task::getFrequency() const
00078         {
00079                 return frequency;
00080         }
00081 
00082         void
00083         Task::setFrequency(double frequency)
00084         {
00085                 this->frequency = frequency; 
00086         }
00087 
00088         double
00089         Task::getWidth() const
00090         {
00091                 return width;
00092         }
00093 
00094         void
00095         Task::setWidth(double width)
00096         {
00097                 this->width = width; 
00098         }
00099 
00100         std::string
00101         Task::getName() const
00102         {
00103                 return this->name;
00104         }
00105 
00106         /*
00107         int
00108         Task::getName() const
00109         {
00110                 return this->id;
00111         }*/
00112         
00113         std::string
00114         Task::getEfficiencyString() const
00115         {
00116                 return this->efficiencyString;
00117         }
00118 
00119         void
00120         Task::setEfficiencyString(const std::string &efficiencyString)
00121         {
00122                 //std::string old = getEfficiencyString();
00123                 
00124                 this->efficiencyString = string(efficiencyString);
00125                 
00126                 // Attemps to compute an efficiency
00127                 /*
00128                 try
00129                 {
00130                         getEfficiency(1);
00131                 } catch (ParseException &e)
00132                 {
00133                         // Restore the old efficiency and bounce the exception
00134                         this->efficiencyString = old;
00135                         throw e;
00136                 }
00137                 */
00138         }
00139 
00140         double
00141         Task::getEfficiency(int p, double def) const
00142         {
00143                 if(getEfficiencyString().find("exprtk") == 0)
00144                 {
00145                         string formula = getEfficiencyString().substr(string("exprtk").size() + 1);
00146                         double W = this->getMaxWidth();
00147                         double tau = this->getWorkload();
00148 
00149                         double output = parseEfficiency(formula, W, tau, p);
00150 
00151                         if(std::isnan(output))
00152                         {
00153                                 throw new ParseException("Could not parse efficiency formula \"" + getEfficiencyString() + "\"");
00154                         }
00155 
00156                         if(output < very_small)
00157                         {
00158                                 output = very_small;
00159                         }
00160 
00161                         return output;          
00162                 }
00163                 else
00164                 {
00165                         stringstream stream(getEfficiencyString());
00166 
00167                         double num;
00168                         size_t count = 1;
00169 
00170                         while(stream >> num && count < (size_t)p)
00171                         {
00172                                 count++;
00173                         }
00174 
00175                         if(count > (size_t)p)
00176                         {
00177                                 num = def;
00178                         }
00179 
00180                         return num;
00181                 }
00182         }
00183 
00184         double
00185         Task::getWorkload() const
00186         {
00187                 return this->workload;
00188         }
00189 
00190         void
00191         Task::setWorkload(double workload)
00192         {
00193                 this->workload = workload;
00194         }
00195 
00196         double
00197         Task::getMaxWidth() const
00198         {
00199                 return this->maxWidth;
00200         }
00201 
00202         void
00203         Task::setMaxWidth(double maxWidth)
00204         {
00205                 this->maxWidth = maxWidth;
00206         }
00207 
00208         bool
00209         Task::isStreaming() const
00210         {
00211                 return this->streaming;
00212         }
00213 
00214         // Write in *number the address of the first character of the number found, or the end of the string str if no number was found.
00215         // Returns the number of characters to parse as number
00216         static size_t
00217         scan_for_number(const char *str, const char **number)
00218         {
00219                 // Make sure the number part is initialized correctly, just in case we start the string with a number.
00220                 *number = str;
00221 
00222                 // Iterate until finding 0-9, + or -
00223                 while((*str < '0' || *str > '9') && !((*str == '-' || *str == '+') && ((*(str + 1) >= '0' && *(str + 1) <= '9') || *(str + 1) == 'e' || *(str + 1) == 'E' || *(str + 1) == '.')) && *str != '\0')
00224                 {
00225                         str++;
00226                         *number = str;
00227                 }
00228 
00229                 // Iterate until finding a dot or a e
00230                 while(*str != '.' && *str != 'e' && *str != 'E' && *str != '\0' && *str >= '0' && *str <= '9')
00231                 {
00232                         str++;
00233                 }
00234 
00235                 // If we find a point, then none is allowed before we find a power of ten sign (e or E, i.e. 56.333E4)
00236                 if(*str == '.')
00237                 {
00238                         while((*str >= '0' && *str <= '9') && *str != 'e' && *str != 'E' && *str != '\0')
00239                         {
00240                                 str++;
00241                         }
00242 
00243                         // Here is the exponent part
00244                         if(*str == 'e' || *str == 'E')
00245                         {
00246                                 // The exponent part can begin with a + or a -
00247                                 if(*str == '+' || *str == '-')
00248                                 {
00249                                         str++;
00250                                 }
00251 
00252                                 // Then can follow either number or a point
00253                                 while((*str >= '0' && *str <= '9') && *str != '.' && *str != '\0')
00254                                 {
00255                                         str++;
00256                                 }
00257                                 
00258                                 // The exponent is decimal
00259                                 if(*str == '.')
00260                                 {
00261                                         // Read more number. No more point or exponent sign is allowed
00262                                         while((*str >= '0' && *str <= '9') && *str != '\0')
00263                                         {
00264                                                 str++;
00265                                         }
00266 
00267                                         // Returns a decimal number with a decimal exponent
00268                                         return ((size_t)str - (size_t)*number) / sizeof(char);
00269                                 }
00270 
00271                                 // Returns a decimal number with an integer exponent
00272                                 return ((size_t)str - (size_t)*number) / sizeof(char);
00273                         }
00274 
00275                         // Returns a decimal number with no exponent
00276                         return ((size_t)str - (size_t)*number) / sizeof(char);
00277                 }
00278 
00279                 // This may be an exponent
00280                 if(*str == 'e' || *str == 'E')
00281                 {
00282                         // Go to next character
00283                         str++;
00284 
00285                         // The exponent part can begin with a + or a -
00286                         if(*str == '+' || *str == '-')
00287                         {
00288                                 str++;
00289                         }
00290 
00291                         // Then can follow either number or a point
00292                         while((*str >= '0' && *str <= '9') && *str != '.' && *str != '\0')
00293                         {
00294                                 str++;
00295                         }
00296                         
00297                         // The exponent is decimal
00298                         if(*str == '.')
00299                         {
00300                                 // Read more number. No more point or exponent sign is allowed
00301                                 while((*str >= '0' && *str <= '9') && *str != '\0')
00302                                 {
00303                                         str++;
00304                                 }
00305 
00306                                 // Returns an integer number with a decimal exponent
00307                                 return ((size_t)str - (size_t)*number) / sizeof(char);
00308                         }
00309 
00310                         // Returns an integer number with an integer exponent
00311                         return ((size_t)str - (size_t)*number) / sizeof(char);
00312                 }
00313 
00314                 // Returns a integer number with no exponent, or no number at all of *str == '\0'
00315                 return ((size_t)str - (size_t)*number) / sizeof(char);
00316         }
00317 
00318         bool
00319         Task::operator<(const Task &other) const
00320         {
00321                 string Me(this->getName());
00322                 string Ot(other.getName());
00323                 const char* me = Me.c_str(); //string(this->getName()).c_str();
00324                 const char* ot = Ot.c_str(); //string(other.getName()).c_str();
00325                 
00326                 //if(string(me).compare(string(ot)) == 0)
00327                 if(this->getName().compare(other.getName()) == 0)
00328                 {
00329                         return false;
00330                 }
00331 
00332                 while(*me != '\0' && *ot != '\0')
00333                 {
00334                         // Find where a number begins for both strings
00335                         // and keep the hypethetic non-number string prefix
00336                         const char *me_num;
00337                         size_t me_num_length = scan_for_number(me, &me_num);
00338                         const char *ot_num;
00339                         size_t ot_num_length = scan_for_number(ot, &ot_num);
00340 
00341                         // Compare the non-number string prefix for both strings
00342                         size_t me_non_number_length = ((ptrdiff_t)me_num - (ptrdiff_t)me) / sizeof(char);
00343                         size_t ot_non_number_length = ((ptrdiff_t)ot_num - (ptrdiff_t)ot) / sizeof(char);
00344                         
00345                         int diff = string(me).substr(0, me_non_number_length).compare(string(ot).substr(0, ot_non_number_length));
00346                         if(diff != 0)
00347                         {
00348                                 return diff < 0;
00349                         }
00350                         else
00351                         {
00352                                 // We can compare the numbers
00353                                 double me_double, ot_double;
00354                                 std::istringstream(string(me_num).substr(0, me_num_length)) >> me_double;
00355                                 std::istringstream(string(ot_num).substr(0, ot_num_length)) >> ot_double;
00356                                 
00357                                 // Go check if there is more text to parse
00358                                 me = me_num + me_num_length;
00359                                 ot = ot_num + ot_num_length;
00360 
00361                                 if(me_double != ot_double)
00362                                 {
00363                                         return me_double < ot_double;
00364                                 }
00365                         }
00366                 }
00367 
00368                 // If one of the string is found empty, just perform a classic string comparison
00369                 return string(me).compare(string(ot)) < 0;
00370         }
00371     
00372         bool
00373         Task::operator==(const Task &other) const
00374         {
00375                 return getName().compare(other.getName()) == 0;
00376         }
00377 
00378         std::string
00379         Task::getModule() const
00380         {
00381                 return this->module;
00382         }
00383 
00384         void
00385         Task::setModule(const std::string &module)
00386         {
00387                 this->module = module;
00388         }
00389 
00390         double
00391         Task::getStartTime() const
00392         {
00393                 return this->start_time;
00394         }
00395 
00396         void
00397         Task::setStartTime(double startTime)
00398         {
00399                 this->start_time = startTime;
00400         }
00401 
00402         double
00403         Task::runtime(double width, double frequency) const
00404         {
00405                 double work = getWorkload();
00406                 work = work / (width * getEfficiency((int)width));
00407                 work = work / frequency;
00408                 
00409                 return work; 
00410         }
00411         
00412         const set<const Link*>&
00413         Task::getProducers() const
00414         {
00415                 return this->producers;
00416         }
00417 
00418         const set<const Link*>&
00419         Task::getConsumers() const
00420         {
00421                 return this->consumers;
00422         }
00423 
00424         set<const Link*>&
00425         Task::getProducers()
00426         {
00427                 return this->producers;
00428         }
00429 
00430         set<const Link*>&
00431         Task::getConsumers()
00432         {
00433                 return this->consumers;
00434         }
00435 }