1 //
2 // Copyright (c) 2017-2020 Advanced Micro Devices, Inc. All rights reserved.
3 //
4 // Permission is hereby granted, free of charge, to any person obtaining a copy
5 // of this software and associated documentation files (the "Software"), to deal
6 // in the Software without restriction, including without limitation the rights
7 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 // copies of the Software, and to permit persons to whom the Software is
9 // furnished to do so, subject to the following conditions:
10 //
11 // The above copyright notice and this permission notice shall be included in
12 // all copies or substantial portions of the Software.
13 //
14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 // THE SOFTWARE.
21 //
22
23 #include "Common.h"
24
StrRangeToPtrList(const StrRange & s,std::vector<uint64_t> & out)25 bool StrRangeToPtrList(const StrRange& s, std::vector<uint64_t>& out)
26 {
27 out.clear();
28 StrRange currRange = { s.beg, nullptr };
29 while(currRange.beg < s.end)
30 {
31 currRange.end = currRange.beg;
32 while(currRange.end < s.end && *currRange.end != ' ')
33 {
34 ++currRange.end;
35 }
36
37 uint64_t ptr = 0;
38 if(!StrRangeToPtr(currRange, ptr))
39 {
40 return false;
41 }
42 out.push_back(ptr);
43
44 currRange.beg = currRange.end + 1;
45 }
46 return true;
47 }
48
49 ////////////////////////////////////////////////////////////////////////////////
50 // LineSplit class
51
GetNextLine(StrRange & out)52 bool LineSplit::GetNextLine(StrRange& out)
53 {
54 if(m_NextLineBeg < m_NumBytes)
55 {
56 out.beg = m_Data + m_NextLineBeg;
57 size_t currLineEnd = m_NextLineBeg;
58 while(currLineEnd < m_NumBytes && m_Data[currLineEnd] != '\n')
59 ++currLineEnd;
60 out.end = m_Data + currLineEnd;
61 // Ignore trailing '\r' to support Windows end of line.
62 if(out.end > out.beg && *(out.end - 1) == '\r')
63 {
64 --out.end;
65 }
66 m_NextLineBeg = currLineEnd + 1; // Past '\n'
67 ++m_NextLineIndex;
68 return true;
69 }
70 else
71 return false;
72 }
73
74 ////////////////////////////////////////////////////////////////////////////////
75 // CsvSplit class
76
Set(const StrRange & line,size_t maxCount)77 void CsvSplit::Set(const StrRange& line, size_t maxCount)
78 {
79 assert(maxCount <= RANGE_COUNT_MAX);
80 m_Line = line;
81 const size_t strLen = line.length();
82 size_t rangeIndex = 0;
83 size_t charIndex = 0;
84 while(charIndex < strLen && rangeIndex < maxCount)
85 {
86 m_Ranges[rangeIndex * 2] = charIndex;
87 while(charIndex < strLen && (rangeIndex + 1 == maxCount || m_Line.beg[charIndex] != ','))
88 ++charIndex;
89 m_Ranges[rangeIndex * 2 + 1] = charIndex;
90 ++rangeIndex;
91 ++charIndex; // Past ','
92 }
93 m_Count = rangeIndex;
94 }
95
96 ////////////////////////////////////////////////////////////////////////////////
97 // class CmdLineParser
98
ReadNextArg(std::string * OutArg)99 bool CmdLineParser::ReadNextArg(std::string *OutArg)
100 {
101 if (m_argv != NULL)
102 {
103 if (m_ArgIndex >= (size_t)m_argc) return false;
104
105 *OutArg = m_argv[m_ArgIndex];
106 m_ArgIndex++;
107 return true;
108 }
109 else
110 {
111 if (m_ArgIndex >= m_CmdLineLength) return false;
112
113 OutArg->clear();
114 bool InsideQuotes = false;
115 while (m_ArgIndex < m_CmdLineLength)
116 {
117 char Ch = m_CmdLine[m_ArgIndex];
118 if (Ch == '\\')
119 {
120 bool FollowedByQuote = false;
121 size_t BackslashCount = 1;
122 size_t TmpIndex = m_ArgIndex + 1;
123 while (TmpIndex < m_CmdLineLength)
124 {
125 char TmpCh = m_CmdLine[TmpIndex];
126 if (TmpCh == '\\')
127 {
128 BackslashCount++;
129 TmpIndex++;
130 }
131 else if (TmpCh == '"')
132 {
133 FollowedByQuote = true;
134 break;
135 }
136 else
137 break;
138 }
139
140 if (FollowedByQuote)
141 {
142 if (BackslashCount % 2 == 0)
143 {
144 for (size_t i = 0; i < BackslashCount / 2; i++)
145 *OutArg += '\\';
146 m_ArgIndex += BackslashCount + 1;
147 InsideQuotes = !InsideQuotes;
148 }
149 else
150 {
151 for (size_t i = 0; i < BackslashCount / 2; i++)
152 *OutArg += '\\';
153 *OutArg += '"';
154 m_ArgIndex += BackslashCount + 1;
155 }
156 }
157 else
158 {
159 for (size_t i = 0; i < BackslashCount; i++)
160 *OutArg += '\\';
161 m_ArgIndex += BackslashCount;
162 }
163 }
164 else if (Ch == '"')
165 {
166 InsideQuotes = !InsideQuotes;
167 m_ArgIndex++;
168 }
169 else if (isspace(Ch))
170 {
171 if (InsideQuotes)
172 {
173 *OutArg += Ch;
174 m_ArgIndex++;
175 }
176 else
177 {
178 m_ArgIndex++;
179 break;
180 }
181 }
182 else
183 {
184 *OutArg += Ch;
185 m_ArgIndex++;
186 }
187 }
188
189 while (m_ArgIndex < m_CmdLineLength && isspace(m_CmdLine[m_ArgIndex]))
190 m_ArgIndex++;
191
192 return true;
193 }
194 }
195
FindShortOpt(char Opt)196 CmdLineParser::SHORT_OPT * CmdLineParser::FindShortOpt(char Opt)
197 {
198 for (size_t i = 0; i < m_ShortOpts.size(); i++)
199 if (m_ShortOpts[i].Opt == Opt)
200 return &m_ShortOpts[i];
201 return NULL;
202 }
203
FindLongOpt(const std::string & Opt)204 CmdLineParser::LONG_OPT * CmdLineParser::FindLongOpt(const std::string &Opt)
205 {
206 for (size_t i = 0; i < m_LongOpts.size(); i++)
207 if (m_LongOpts[i].Opt == Opt)
208 return &m_LongOpts[i];
209 return NULL;
210 }
211
CmdLineParser(int argc,char ** argv)212 CmdLineParser::CmdLineParser(int argc, char **argv) :
213 m_argv(argv),
214 m_CmdLine(NULL),
215 m_argc(argc),
216 m_CmdLineLength(0),
217 m_ArgIndex(1),
218 m_InsideMultioption(false),
219 m_LastArgIndex(0),
220 m_LastOptId(0)
221 {
222 assert(argc > 0);
223 assert(argv != NULL);
224 }
225
CmdLineParser(const char * CmdLine)226 CmdLineParser::CmdLineParser(const char *CmdLine) :
227 m_argv(NULL),
228 m_CmdLine(CmdLine),
229 m_argc(0),
230 m_ArgIndex(0),
231 m_InsideMultioption(false),
232 m_LastArgIndex(0),
233 m_LastOptId(0)
234 {
235 assert(CmdLine != NULL);
236
237 m_CmdLineLength = strlen(m_CmdLine);
238
239 while (m_ArgIndex < m_CmdLineLength && isspace(m_CmdLine[m_ArgIndex]))
240 m_ArgIndex++;
241 }
242
RegisterOpt(uint32_t Id,char Opt,bool Parameter)243 void CmdLineParser::RegisterOpt(uint32_t Id, char Opt, bool Parameter)
244 {
245 assert(Opt != '\0');
246
247 m_ShortOpts.push_back(SHORT_OPT(Id, Opt, Parameter));
248 }
249
RegisterOpt(uint32_t Id,const std::string & Opt,bool Parameter)250 void CmdLineParser::RegisterOpt(uint32_t Id, const std::string &Opt, bool Parameter)
251 {
252 assert(!Opt.empty());
253
254 m_LongOpts.push_back(LONG_OPT(Id, Opt, Parameter));
255 }
256
ReadNext()257 CmdLineParser::RESULT CmdLineParser::ReadNext()
258 {
259 if (m_InsideMultioption)
260 {
261 assert(m_LastArgIndex < m_LastArg.length());
262 SHORT_OPT *so = FindShortOpt(m_LastArg[m_LastArgIndex]);
263 if (so == NULL)
264 {
265 m_LastOptId = 0;
266 m_LastParameter.clear();
267 return CmdLineParser::RESULT_ERROR;
268 }
269 if (so->Parameter)
270 {
271 if (m_LastArg.length() == m_LastArgIndex+1)
272 {
273 if (!ReadNextArg(&m_LastParameter))
274 {
275 m_LastOptId = 0;
276 m_LastParameter.clear();
277 return CmdLineParser::RESULT_ERROR;
278 }
279 m_InsideMultioption = false;
280 m_LastOptId = so->Id;
281 return CmdLineParser::RESULT_OPT;
282 }
283 else if (m_LastArg[m_LastArgIndex+1] == '=')
284 {
285 m_InsideMultioption = false;
286 m_LastParameter = m_LastArg.substr(m_LastArgIndex+2);
287 m_LastOptId = so->Id;
288 return CmdLineParser::RESULT_OPT;
289 }
290 else
291 {
292 m_InsideMultioption = false;
293 m_LastParameter = m_LastArg.substr(m_LastArgIndex+1);
294 m_LastOptId = so->Id;
295 return CmdLineParser::RESULT_OPT;
296 }
297 }
298 else
299 {
300 if (m_LastArg.length() == m_LastArgIndex+1)
301 {
302 m_InsideMultioption = false;
303 m_LastParameter.clear();
304 m_LastOptId = so->Id;
305 return CmdLineParser::RESULT_OPT;
306 }
307 else
308 {
309 m_LastArgIndex++;
310
311 m_LastParameter.clear();
312 m_LastOptId = so->Id;
313 return CmdLineParser::RESULT_OPT;
314 }
315 }
316 }
317 else
318 {
319 if (!ReadNextArg(&m_LastArg))
320 {
321 m_LastParameter.clear();
322 m_LastOptId = 0;
323 return CmdLineParser::RESULT_END;
324 }
325
326 if (!m_LastArg.empty() && m_LastArg[0] == '-')
327 {
328 if (m_LastArg.length() > 1 && m_LastArg[1] == '-')
329 {
330 size_t EqualIndex = m_LastArg.find('=', 2);
331 if (EqualIndex != std::string::npos)
332 {
333 LONG_OPT *lo = FindLongOpt(m_LastArg.substr(2, EqualIndex-2));
334 if (lo == NULL || lo->Parameter == false)
335 {
336 m_LastOptId = 0;
337 m_LastParameter.clear();
338 return CmdLineParser::RESULT_ERROR;
339 }
340 m_LastParameter = m_LastArg.substr(EqualIndex+1);
341 m_LastOptId = lo->Id;
342 return CmdLineParser::RESULT_OPT;
343 }
344 else
345 {
346 LONG_OPT *lo = FindLongOpt(m_LastArg.substr(2));
347 if (lo == NULL)
348 {
349 m_LastOptId = 0;
350 m_LastParameter.clear();
351 return CmdLineParser::RESULT_ERROR;
352 }
353 if (lo->Parameter)
354 {
355 if (!ReadNextArg(&m_LastParameter))
356 {
357 m_LastOptId = 0;
358 m_LastParameter.clear();
359 return CmdLineParser::RESULT_ERROR;
360 }
361 }
362 else
363 m_LastParameter.clear();
364 m_LastOptId = lo->Id;
365 return CmdLineParser::RESULT_OPT;
366 }
367 }
368 else
369 {
370 if (m_LastArg.length() < 2)
371 {
372 m_LastOptId = 0;
373 m_LastParameter.clear();
374 return CmdLineParser::RESULT_ERROR;
375 }
376 SHORT_OPT *so = FindShortOpt(m_LastArg[1]);
377 if (so == NULL)
378 {
379 m_LastOptId = 0;
380 m_LastParameter.clear();
381 return CmdLineParser::RESULT_ERROR;
382 }
383 if (so->Parameter)
384 {
385 if (m_LastArg.length() == 2)
386 {
387 if (!ReadNextArg(&m_LastParameter))
388 {
389 m_LastOptId = 0;
390 m_LastParameter.clear();
391 return CmdLineParser::RESULT_ERROR;
392 }
393 m_LastOptId = so->Id;
394 return CmdLineParser::RESULT_OPT;
395 }
396 else if (m_LastArg[2] == '=')
397 {
398 m_LastParameter = m_LastArg.substr(3);
399 m_LastOptId = so->Id;
400 return CmdLineParser::RESULT_OPT;
401 }
402 else
403 {
404 m_LastParameter = m_LastArg.substr(2);
405 m_LastOptId = so->Id;
406 return CmdLineParser::RESULT_OPT;
407 }
408 }
409 else
410 {
411 if (m_LastArg.length() == 2)
412 {
413 m_LastParameter.clear();
414 m_LastOptId = so->Id;
415 return CmdLineParser::RESULT_OPT;
416 }
417 else
418 {
419 m_InsideMultioption = true;
420 m_LastArgIndex = 2;
421
422 m_LastParameter.clear();
423 m_LastOptId = so->Id;
424 return CmdLineParser::RESULT_OPT;
425 }
426 }
427 }
428 }
429 else if (!m_LastArg.empty() && m_LastArg[0] == '/')
430 {
431 size_t EqualIndex = m_LastArg.find('=', 1);
432 if (EqualIndex != std::string::npos)
433 {
434 if (EqualIndex == 2)
435 {
436 SHORT_OPT *so = FindShortOpt(m_LastArg[1]);
437 if (so != NULL)
438 {
439 if (so->Parameter == false)
440 {
441 m_LastOptId = 0;
442 m_LastParameter.clear();
443 return CmdLineParser::RESULT_ERROR;
444 }
445 m_LastParameter = m_LastArg.substr(EqualIndex+1);
446 m_LastOptId = so->Id;
447 return CmdLineParser::RESULT_OPT;
448 }
449 }
450 LONG_OPT *lo = FindLongOpt(m_LastArg.substr(1, EqualIndex-1));
451 if (lo == NULL || lo->Parameter == false)
452 {
453 m_LastOptId = 0;
454 m_LastParameter.clear();
455 return CmdLineParser::RESULT_ERROR;
456 }
457 m_LastParameter = m_LastArg.substr(EqualIndex+1);
458 m_LastOptId = lo->Id;
459 return CmdLineParser::RESULT_OPT;
460 }
461 else
462 {
463 if (m_LastArg.length() == 2)
464 {
465 SHORT_OPT *so = FindShortOpt(m_LastArg[1]);
466 if (so != NULL)
467 {
468 if (so->Parameter)
469 {
470 if (!ReadNextArg(&m_LastParameter))
471 {
472 m_LastOptId = 0;
473 m_LastParameter.clear();
474 return CmdLineParser::RESULT_ERROR;
475 }
476 }
477 else
478 m_LastParameter.clear();
479 m_LastOptId = so->Id;
480 return CmdLineParser::RESULT_OPT;
481 }
482 }
483 LONG_OPT *lo = FindLongOpt(m_LastArg.substr(1));
484 if (lo == NULL)
485 {
486 m_LastOptId = 0;
487 m_LastParameter.clear();
488 return CmdLineParser::RESULT_ERROR;
489 }
490 if (lo->Parameter)
491 {
492 if (!ReadNextArg(&m_LastParameter))
493 {
494 m_LastOptId = 0;
495 m_LastParameter.clear();
496 return CmdLineParser::RESULT_ERROR;
497 }
498 }
499 else
500 m_LastParameter.clear();
501 m_LastOptId = lo->Id;
502 return CmdLineParser::RESULT_OPT;
503 }
504 }
505 else
506 {
507 m_LastOptId = 0;
508 m_LastParameter = m_LastArg;
509 return CmdLineParser::RESULT_PARAMETER;
510 }
511 }
512 }
513
GetOptId()514 uint32_t CmdLineParser::GetOptId()
515 {
516 return m_LastOptId;
517 }
518
GetParameter()519 const std::string & CmdLineParser::GetParameter()
520 {
521 return m_LastParameter;
522 }
523
524 ////////////////////////////////////////////////////////////////////////////////
525 // Glolals
526
527 /*
528
529 void SetConsoleColor(CONSOLE_COLOR color)
530 {
531 WORD attr = 0;
532 switch(color)
533 {
534 case CONSOLE_COLOR::INFO:
535 attr = FOREGROUND_INTENSITY;;
536 break;
537 case CONSOLE_COLOR::NORMAL:
538 attr = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE;
539 break;
540 case CONSOLE_COLOR::WARNING:
541 attr = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY;
542 break;
543 case CONSOLE_COLOR::ERROR_:
544 attr = FOREGROUND_RED | FOREGROUND_INTENSITY;
545 break;
546 default:
547 assert(0);
548 }
549
550 HANDLE out = GetStdHandle(STD_OUTPUT_HANDLE);
551 SetConsoleTextAttribute(out, attr);
552 }
553
554 void PrintMessage(CONSOLE_COLOR color, const char* msg)
555 {
556 if(color != CONSOLE_COLOR::NORMAL)
557 SetConsoleColor(color);
558
559 printf("%s\n", msg);
560
561 if (color != CONSOLE_COLOR::NORMAL)
562 SetConsoleColor(CONSOLE_COLOR::NORMAL);
563 }
564
565 void PrintMessage(CONSOLE_COLOR color, const wchar_t* msg)
566 {
567 if(color != CONSOLE_COLOR::NORMAL)
568 SetConsoleColor(color);
569
570 wprintf(L"%s\n", msg);
571
572 if (color != CONSOLE_COLOR::NORMAL)
573 SetConsoleColor(CONSOLE_COLOR::NORMAL);
574 }
575
576 static const size_t CONSOLE_SMALL_BUF_SIZE = 256;
577
578 void PrintMessageV(CONSOLE_COLOR color, const char* format, va_list argList)
579 {
580 size_t dstLen = (size_t)::_vscprintf(format, argList);
581 if(dstLen)
582 {
583 bool useSmallBuf = dstLen < CONSOLE_SMALL_BUF_SIZE;
584 char smallBuf[CONSOLE_SMALL_BUF_SIZE];
585 std::vector<char> bigBuf(useSmallBuf ? 0 : dstLen + 1);
586 char* bufPtr = useSmallBuf ? smallBuf : bigBuf.data();
587 ::vsprintf_s(bufPtr, dstLen + 1, format, argList);
588 PrintMessage(color, bufPtr);
589 }
590 }
591
592 void PrintMessageV(CONSOLE_COLOR color, const wchar_t* format, va_list argList)
593 {
594 size_t dstLen = (size_t)::_vcwprintf(format, argList);
595 if(dstLen)
596 {
597 bool useSmallBuf = dstLen < CONSOLE_SMALL_BUF_SIZE;
598 wchar_t smallBuf[CONSOLE_SMALL_BUF_SIZE];
599 std::vector<wchar_t> bigBuf(useSmallBuf ? 0 : dstLen + 1);
600 wchar_t* bufPtr = useSmallBuf ? smallBuf : bigBuf.data();
601 ::vswprintf_s(bufPtr, dstLen + 1, format, argList);
602 PrintMessage(color, bufPtr);
603 }
604 }
605
606 void PrintMessageF(CONSOLE_COLOR color, const char* format, ...)
607 {
608 va_list argList;
609 va_start(argList, format);
610 PrintMessageV(color, format, argList);
611 va_end(argList);
612 }
613
614 void PrintMessageF(CONSOLE_COLOR color, const wchar_t* format, ...)
615 {
616 va_list argList;
617 va_start(argList, format);
618 PrintMessageV(color, format, argList);
619 va_end(argList);
620 }
621
622 void PrintWarningF(const char* format, ...)
623 {
624 va_list argList;
625 va_start(argList, format);
626 PrintMessageV(CONSOLE_COLOR::WARNING, format, argList);
627 va_end(argList);
628 }
629
630 void PrintWarningF(const wchar_t* format, ...)
631 {
632 va_list argList;
633 va_start(argList, format);
634 PrintMessageV(CONSOLE_COLOR::WARNING, format, argList);
635 va_end(argList);
636 }
637
638 void PrintErrorF(const char* format, ...)
639 {
640 va_list argList;
641 va_start(argList, format);
642 PrintMessageV(CONSOLE_COLOR::WARNING, format, argList);
643 va_end(argList);
644 }
645
646 void PrintErrorF(const wchar_t* format, ...)
647 {
648 va_list argList;
649 va_start(argList, format);
650 PrintMessageV(CONSOLE_COLOR::WARNING, format, argList);
651 va_end(argList);
652 }
653 */
654
SecondsToFriendlyStr(float seconds,std::string & out)655 void SecondsToFriendlyStr(float seconds, std::string& out)
656 {
657 if(seconds == 0.f)
658 {
659 out = "0";
660 return;
661 }
662
663 if (seconds < 0.f)
664 {
665 out = "-";
666 seconds = -seconds;
667 }
668 else
669 {
670 out.clear();
671 }
672
673 char s[32];
674
675 // #.### ns
676 if(seconds < 1e-6)
677 {
678 sprintf_s(s, "%.3f ns", seconds * 1e9);
679 out += s;
680 }
681 // #.### us
682 else if(seconds < 1e-3)
683 {
684 sprintf_s(s, "%.3f us", seconds * 1e6);
685 out += s;
686 }
687 // #.### ms
688 else if(seconds < 1.f)
689 {
690 sprintf_s(s, "%.3f ms", seconds * 1e3);
691 out += s;
692 }
693 // #.### s
694 else if(seconds < 60.f)
695 {
696 sprintf_s(s, "%.3f s", seconds);
697 out += s;
698 }
699 else
700 {
701 uint64_t seconds_u = (uint64_t)seconds;
702 // "#:## min"
703 if (seconds_u < 3600)
704 {
705 uint64_t minutes = seconds_u / 60;
706 seconds_u -= minutes * 60;
707 sprintf_s(s, "%llu:%02llu min", minutes, seconds_u);
708 out += s;
709 }
710 // "#:##:## h"
711 else
712 {
713 uint64_t minutes = seconds_u / 60;
714 seconds_u -= minutes * 60;
715 uint64_t hours = minutes / 60;
716 minutes -= hours * 60;
717 sprintf_s(s, "%llu:%02llu:%02llu h", hours, minutes, seconds_u);
718 out += s;
719 }
720 }
721 }
722