pelib
2.0.0
|
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 }