You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

153 lines
4.8 KiB

  1. #pragma once
  2. #ifdef PROFILING
  3. # include <stdlib.h>
  4. # include <stdio.h>
  5. # include <string.h>
  6. # include <time.h>
  7. # include "./platform.hpp"
  8. #ifdef FTB_WINDOWS
  9. # include <Windows.h>
  10. #else
  11. # include <fcntl.h>
  12. # include <sys/stat.h>
  13. # include <sys/time.h>
  14. # include <sys/time.h>
  15. # include <stdint.h>
  16. # include <stdbool.h>
  17. # include <stddef.h>
  18. /* Helpful conversion constants. */
  19. static const unsigned usec_per_sec = 1000000;
  20. static const unsigned usec_per_msec = 1000;
  21. /* These functions are written to match the win32
  22. signatures and behavior as closely as possible.
  23. */
  24. bool QueryPerformanceFrequency(int64_t *frequency)
  25. {
  26. /* gettimeofday reports to microsecond accuracy. */
  27. *frequency = usec_per_sec;
  28. return true;
  29. }
  30. bool QueryPerformanceCounter(int64_t *performance_count)
  31. {
  32. struct timeval time;
  33. /* Grab the current time. */
  34. gettimeofday(&time, NULL);
  35. *performance_count = time.tv_usec + /* Microseconds. */
  36. time.tv_sec * usec_per_sec; /* Seconds. */
  37. return true;
  38. }
  39. #endif
  40. struct Profiler {
  41. #ifdef FTB_WINDOWS
  42. LARGE_INTEGER tmp_time;
  43. #else
  44. int64_t tmp_time;
  45. #endif
  46. // same for all threads
  47. inline static char file_template[100] = "\0";
  48. // thread local
  49. inline thread_local static bool is_initialized = false;
  50. inline thread_local static size_t thread_id = -1;
  51. inline thread_local static int call_depth = 0;
  52. inline thread_local static FILE* out_file = nullptr;
  53. Profiler(const char* file, const char* name, const int line, const char* comment1, const char* comment2) {
  54. call_depth += 1;
  55. // if we never used this thread before
  56. if (!is_initialized) {
  57. thread_id = (size_t)&thread_id;
  58. time_t t = time(NULL);
  59. tm* tm_i = localtime(&t);
  60. // create folder
  61. #ifdef FTB_WINDOWS
  62. SECURITY_ATTRIBUTES sa;
  63. sa.nLength = sizeof(sa);
  64. sa.lpSecurityDescriptor = NULL;
  65. sa.bInheritHandle = FALSE;
  66. CreateDirectoryA("profiler_reports", &sa);
  67. // _mkdir("./profiler_reports/");
  68. #else
  69. mkdir("./profiler_reports/", S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
  70. #endif
  71. // if we never even created the shared file name template
  72. if (!file_template[0]) {
  73. // make sure folder exists
  74. sprintf(file_template, "./profiler_reports/%02d.%02d.%04d-%02d.%02d.%02d-%%zd-profiler.report",
  75. tm_i->tm_mday, tm_i->tm_mon+1, tm_i->tm_year+1900,
  76. tm_i->tm_hour, tm_i->tm_min, tm_i->tm_sec);
  77. }
  78. char file_name[100];
  79. sprintf(file_name, file_template, thread_id);
  80. // printf("Hello I am %zd\n", thread_id);
  81. out_file = fopen(file_name, "w");
  82. if (!out_file) {
  83. printf("could not open %s\n", file_name);
  84. }
  85. // initially write the performance frequency
  86. QueryPerformanceFrequency(&tmp_time);
  87. #ifdef FTB_WINDOWS
  88. fprintf(out_file, "%lld,,,,\n", tmp_time.QuadPart);
  89. #else
  90. fprintf(out_file, "%ld,,,,\n", tmp_time);
  91. #endif
  92. is_initialized = true;
  93. }
  94. QueryPerformanceCounter(&tmp_time);
  95. #ifdef FTB_WINDOWS
  96. fprintf(out_file, "->,%lld,%s,%s,%d,%s,%s\n",
  97. tmp_time.QuadPart, name, file,
  98. line, comment1, comment2);
  99. #else
  100. fprintf(out_file, "->,%ld,%s,%s,%d,%s,%s\n",
  101. tmp_time, name, file,
  102. line, comment1, comment2);
  103. #endif
  104. };
  105. ~Profiler() {
  106. call_depth -= 1;
  107. QueryPerformanceCounter(&tmp_time);
  108. #ifdef FTB_WINDOWS
  109. fprintf(out_file, "<-,%lld,,,,,\n", tmp_time.QuadPart);
  110. #else
  111. fprintf(out_file, "<-,%ld,,,,,\n", tmp_time);
  112. #endif
  113. if (call_depth == 0)
  114. fflush(out_file);
  115. };
  116. };
  117. # define profile_this() Profiler profiler(__FILE__, __FUNCTION__, __LINE__, "", "")
  118. # define profile_with_name(name) Profiler profiler(__FILE__, name, __LINE__, "", "")
  119. # define profile_with_comment(c1) Profiler profiler(__FILE__, __FUNCTION__, __LINE__, c1, "")
  120. # define profile_with_comments(c1,c2) Profiler profiler(__FILE__, __FUNCTION__, __LINE__, c1, c2)
  121. # define profile_with_name_and_comment(name,c1) Profiler profiler(__FILE__, name, __LINE__, c1, "")
  122. # define profile_with_name_and_comments(name,c1,c2) Profiler profiler(__FILE__, name, __LINE__, c1, c2)
  123. #else
  124. # define profile_this() do {} while(0)
  125. # define profile_with_name(name) do {} while(0)
  126. # define profile_with_comment(c1) do {} while(0)
  127. # define profile_with_comments(c1,c2) do {} while(0)
  128. # define profile_with_name_and_comment(name,c1) do {} while(0)
  129. # define profile_with_name_and_comments(name,c1,c2) do {} while(0)
  130. #endif