log.cc 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371
  1. #include <unistd.h>
  2. #include <sys/time.h>
  3. #include <sys/syscall.h>
  4. #include <stdarg.h>
  5. #include <string.h>
  6. #include <signal.h>
  7. #include "log.h"
  8. #include "config.h"
  9. #include "simulator.h"
  10. #include "core_manager.h"
  11. #include "config.hpp"
  12. #include "circular_log.h"
  13. // When debugging, it helps to be able to attach to the thread you would like to investigate directly,
  14. // instead of running the program from the beginning in GDB.
  15. //#define LOG_SIGSTOP_ON_ERROR
  16. Log *Log::_singleton;
  17. const size_t Log::MODULE_LENGTH;
  18. static String formatFileName(const char* s)
  19. {
  20. return Sim()->getConfig()->formatOutputFileName(s);
  21. }
  22. Log::Log(Config &config)
  23. : _coreCount(config.getTotalCores())
  24. , _startTime(0)
  25. {
  26. initFileDescriptors();
  27. getEnabledModules();
  28. getDisabledModules();
  29. _loggingEnabled = initIsLoggingEnabled();
  30. _anyLoggingEnabled = (!_enabledModules.empty()) || _loggingEnabled;
  31. assert(_singleton == NULL);
  32. _singleton = this;
  33. if (Sim()->getConfig()->getCircularLogEnabled())
  34. CircularLog::init(formatFileName("sim.clog"));
  35. }
  36. Log::~Log()
  37. {
  38. _singleton = NULL;
  39. for (core_id_t i = 0; i < _coreCount; i++)
  40. {
  41. if (_coreFiles[i])
  42. fclose(_coreFiles[i]);
  43. if (_simFiles[i])
  44. fclose(_simFiles[i]);
  45. }
  46. delete [] _coreLocks;
  47. delete [] _simLocks;
  48. delete [] _coreFiles;
  49. delete [] _simFiles;
  50. if (_systemFile)
  51. fclose(_systemFile);
  52. CircularLog::fini();
  53. }
  54. Log* Log::getSingleton()
  55. {
  56. assert(_singleton);
  57. return _singleton;
  58. }
  59. bool Log::isEnabled(const char* module)
  60. {
  61. // either the module is specifically enabled, or all logging is
  62. // enabled and this one isn't disabled
  63. return _anyLoggingEnabled &&
  64. (_enabledModules.find(module) != _enabledModules.end()
  65. || (_loggingEnabled && _disabledModules.find(module) == _disabledModules.end())
  66. );
  67. }
  68. void Log::initFileDescriptors()
  69. {
  70. _coreFiles = new FILE* [_coreCount];
  71. _simFiles = new FILE* [_coreCount];
  72. for (core_id_t i = 0; i < _coreCount; i++)
  73. {
  74. _coreFiles[i] = NULL;
  75. _simFiles[i] = NULL;
  76. }
  77. _coreLocks = new Lock [_coreCount];
  78. _simLocks = new Lock [_coreCount];
  79. _systemFile = NULL;
  80. }
  81. void Log::parseModules(std::set<String> &mods, String list)
  82. {
  83. String delimiters = " ";
  84. String::size_type lastPos = list.find_first_not_of(delimiters, 0);
  85. String::size_type pos = list.find_first_of(delimiters, lastPos);
  86. std::set<String> unformatted;
  87. while (String::npos != pos || String::npos != lastPos)
  88. {
  89. unformatted.insert(list.substr(lastPos, pos - lastPos));
  90. lastPos = list.find_first_not_of(delimiters, pos);
  91. pos = list.find_first_of(delimiters, lastPos);
  92. }
  93. for (std::set<String>::iterator it = unformatted.begin();
  94. it != unformatted.end();
  95. it++)
  96. {
  97. String formatted;
  98. for (unsigned int i = 0; i < std::min(MODULE_LENGTH, it->length()); i++)
  99. {
  100. formatted.push_back((*it)[i]);
  101. }
  102. for (unsigned int i = formatted.length(); i < MODULE_LENGTH; i++)
  103. {
  104. formatted.push_back(' ');
  105. }
  106. assert(formatted.length() == MODULE_LENGTH);
  107. mods.insert(formatted);
  108. }
  109. }
  110. void Log::getDisabledModules()
  111. {
  112. try
  113. {
  114. String disabledModules = Sim()->getCfg()->getString("log/disabled_modules");
  115. parseModules(_disabledModules, disabledModules);
  116. }
  117. catch (...)
  118. {
  119. // FIXME: is log initialized at this point?
  120. LOG_PRINT_ERROR("Exception while reading disabled modules.");
  121. }
  122. }
  123. void Log::getEnabledModules()
  124. {
  125. try
  126. {
  127. String enabledModules = Sim()->getCfg()->getString("log/enabled_modules");
  128. parseModules(_enabledModules, enabledModules);
  129. }
  130. catch (...)
  131. {
  132. // FIXME: is log initialized at this point?
  133. LOG_PRINT_ERROR("Exception while reading enabled modules.");
  134. }
  135. }
  136. bool Log::initIsLoggingEnabled()
  137. {
  138. try
  139. {
  140. return Sim()->getCfg()->getBool("log/enabled");
  141. }
  142. catch (...)
  143. {
  144. assert(false);
  145. return false;
  146. }
  147. }
  148. UInt64 Log::getTimestamp()
  149. {
  150. timeval t;
  151. gettimeofday(&t, NULL);
  152. UInt64 time = (((UInt64)t.tv_sec) * 1000000 + t.tv_usec);
  153. if (_startTime == 0) _startTime = time;
  154. return time - _startTime;
  155. }
  156. void Log::discoverCore(core_id_t *core_id, bool *sim_thread)
  157. {
  158. CoreManager *core_manager;
  159. if (!Sim() || !(core_manager = Sim()->getCoreManager()))
  160. {
  161. *core_id = INVALID_CORE_ID;
  162. *sim_thread = false;
  163. return;
  164. }
  165. else
  166. {
  167. *core_id = core_manager->getCurrentCoreID();
  168. *sim_thread = core_manager->amiSimThread();
  169. }
  170. }
  171. void Log::getFile(core_id_t core_id, bool sim_thread, FILE **file, Lock **lock)
  172. {
  173. // we use on-demand file allocation to prevent contention between
  174. // processes for files
  175. *file = NULL;
  176. *lock = NULL;
  177. if (core_id == INVALID_CORE_ID)
  178. {
  179. if (_systemFile == NULL)
  180. {
  181. char filename[256];
  182. sprintf(filename, "system.log");
  183. _systemFile = fopen(formatFileName(filename).c_str(), "w");
  184. assert(_systemFile != NULL);
  185. }
  186. *file = _systemFile;
  187. *lock = &_systemLock;
  188. }
  189. else if (sim_thread)
  190. {
  191. // sim thread file
  192. if (_simFiles[core_id] == NULL)
  193. {
  194. assert(core_id < _coreCount);
  195. char filename[256];
  196. sprintf(filename, "sim_%u.log", core_id);
  197. _simFiles[core_id] = fopen(formatFileName(filename).c_str(), "w");
  198. assert(_simFiles[core_id] != NULL);
  199. }
  200. *file = _simFiles[core_id];
  201. *lock = &_simLocks[core_id];
  202. }
  203. else
  204. {
  205. // core file
  206. if (_coreFiles[core_id] == NULL)
  207. {
  208. assert(core_id < _coreCount);
  209. char filename[256];
  210. sprintf(filename, "app_%u.log", core_id);
  211. _coreFiles[core_id] = fopen(formatFileName(filename).c_str(), "w");
  212. assert(_coreFiles[core_id] != NULL);
  213. }
  214. // Core file
  215. *file = _coreFiles[core_id];
  216. *lock = &_coreLocks[core_id];
  217. }
  218. }
  219. String Log::getModule(const char *filename)
  220. {
  221. // TODO: Give each thread a _module map to cache entries. (Hash table?)
  222. // ScopedLock sl(_modules_lock);
  223. // map<const char*, String>::const_iterator it = _modules.find(filename);
  224. // if (it != _modules.end())
  225. // {
  226. // return it->second;
  227. // }
  228. // else
  229. // {
  230. // build module string
  231. String mod;
  232. // find actual file name ...
  233. const char *ptr = strrchr(filename, '/');
  234. if (ptr != NULL)
  235. filename = ptr + 1;
  236. for (UInt32 i = 0; i < MODULE_LENGTH && filename[i] != '\0'; i++)
  237. mod.push_back(filename[i]);
  238. while (mod.length() < MODULE_LENGTH)
  239. mod.push_back(' ');
  240. // pair<const char*, String> p(filename, mod);
  241. // _modules.insert(p);
  242. return mod;
  243. // }
  244. }
  245. void Log::log(ErrorState err, const char* source_file, SInt32 source_line, const char *format, ...)
  246. {
  247. core_id_t core_id;
  248. bool sim_thread;
  249. discoverCore(&core_id, &sim_thread);
  250. FILE *file;
  251. Lock *lock;
  252. getFile(core_id, sim_thread, &file, &lock);
  253. int tid = syscall(__NR_gettid);
  254. char message[512];
  255. char *p = message;
  256. // This is ugly, but it just prints the time stamp, core number, source file/line
  257. if (core_id != INVALID_CORE_ID) // valid core id
  258. p += sprintf(p, "%-10llu [%5d] [%2i]%s[%s:%4d] ", (long long unsigned int) getTimestamp(), tid, core_id, (sim_thread ? "* " : " "), source_file, source_line);
  259. else // who knows
  260. p += sprintf(p, "%-10llu [%5d] [ ] [%s:%4d] ", (long long unsigned int) getTimestamp(), tid, source_file, source_line);
  261. switch (err)
  262. {
  263. case None:
  264. default:
  265. break;
  266. case Warning:
  267. p += sprintf(p, "*WARNING* ");
  268. break;
  269. case Error:
  270. p += sprintf(p, "*ERROR* ");
  271. break;
  272. };
  273. va_list args;
  274. va_start(args, format);
  275. p += vsprintf(p, format, args);
  276. va_end(args);
  277. p += sprintf(p, "\n");
  278. lock->acquire();
  279. fputs(message, file);
  280. fflush(file);
  281. lock->release();
  282. switch (err)
  283. {
  284. case Error:
  285. CircularLog::fini();
  286. fflush(NULL);
  287. fputs(message, stderr);
  288. #ifndef LOG_SIGSTOP_ON_ERROR
  289. abort();
  290. #else
  291. while (1)
  292. {
  293. raise(SIGSTOP);
  294. }
  295. #endif
  296. break;
  297. case Warning:
  298. fputs(message, stderr);
  299. break;
  300. case None:
  301. default:
  302. break;
  303. }
  304. }