util_profiling.cpp 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180
  1. /*
  2. * Copyright 2011-2018 Blender Foundation
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. #include "util/util_algorithm.h"
  17. #include "util/util_profiling.h"
  18. #include "util/util_set.h"
  19. CCL_NAMESPACE_BEGIN
  20. Profiler::Profiler() : do_stop_worker(true), worker(NULL)
  21. {
  22. }
  23. Profiler::~Profiler()
  24. {
  25. assert(worker == NULL);
  26. }
  27. void Profiler::run()
  28. {
  29. uint64_t updates = 0;
  30. auto start_time = std::chrono::system_clock::now();
  31. while (!do_stop_worker) {
  32. thread_scoped_lock lock(mutex);
  33. foreach (ProfilingState *state, states) {
  34. uint32_t cur_event = state->event;
  35. int32_t cur_shader = state->shader;
  36. int32_t cur_object = state->object;
  37. /* The state reads/writes should be atomic, but just to be sure
  38. * check the values for validity anyways. */
  39. if (cur_event < PROFILING_NUM_EVENTS) {
  40. event_samples[cur_event]++;
  41. }
  42. if (cur_shader >= 0 && cur_shader < shader_samples.size()) {
  43. /* Only consider the active shader during events whose runtime significantly depends on it.
  44. */
  45. if (((cur_event >= PROFILING_SHADER_EVAL) && (cur_event <= PROFILING_SUBSURFACE)) ||
  46. ((cur_event >= PROFILING_CLOSURE_EVAL) &&
  47. (cur_event <= PROFILING_CLOSURE_VOLUME_SAMPLE))) {
  48. shader_samples[cur_shader]++;
  49. }
  50. }
  51. if (cur_object >= 0 && cur_object < object_samples.size()) {
  52. object_samples[cur_object]++;
  53. }
  54. }
  55. lock.unlock();
  56. /* Relative waits always overshoot a bit, so just waiting 1ms every
  57. * time would cause the sampling to drift over time.
  58. * By keeping track of the absolute time, the wait times correct themselves -
  59. * if one wait overshoots a lot, the next one will be shorter to compensate. */
  60. updates++;
  61. std::this_thread::sleep_until(start_time + updates * std::chrono::milliseconds(1));
  62. }
  63. }
  64. void Profiler::reset(int num_shaders, int num_objects)
  65. {
  66. bool running = (worker != NULL);
  67. if (running) {
  68. stop();
  69. }
  70. /* Resize and clear the accumulation vectors. */
  71. shader_hits.assign(num_shaders, 0);
  72. object_hits.assign(num_objects, 0);
  73. event_samples.assign(PROFILING_NUM_EVENTS, 0);
  74. shader_samples.assign(num_shaders, 0);
  75. object_samples.assign(num_objects, 0);
  76. if (running) {
  77. start();
  78. }
  79. }
  80. void Profiler::start()
  81. {
  82. assert(worker == NULL);
  83. do_stop_worker = false;
  84. worker = new thread(function_bind(&Profiler::run, this));
  85. }
  86. void Profiler::stop()
  87. {
  88. if (worker != NULL) {
  89. do_stop_worker = true;
  90. worker->join();
  91. delete worker;
  92. worker = NULL;
  93. }
  94. }
  95. void Profiler::add_state(ProfilingState *state)
  96. {
  97. thread_scoped_lock lock(mutex);
  98. /* Add the ProfilingState from the list of sampled states. */
  99. assert(std::find(states.begin(), states.end(), state) == states.end());
  100. states.push_back(state);
  101. /* Resize thread-local hit counters. */
  102. state->shader_hits.assign(shader_hits.size(), 0);
  103. state->object_hits.assign(object_hits.size(), 0);
  104. /* Initialize the state. */
  105. state->event = PROFILING_UNKNOWN;
  106. state->shader = -1;
  107. state->object = -1;
  108. state->active = true;
  109. }
  110. void Profiler::remove_state(ProfilingState *state)
  111. {
  112. thread_scoped_lock lock(mutex);
  113. /* Remove the ProfilingState from the list of sampled states. */
  114. states.erase(std::remove(states.begin(), states.end(), state), states.end());
  115. state->active = false;
  116. /* Merge thread-local hit counters. */
  117. assert(shader_hits.size() == state->shader_hits.size());
  118. for (int i = 0; i < shader_hits.size(); i++) {
  119. shader_hits[i] += state->shader_hits[i];
  120. }
  121. assert(object_hits.size() == state->object_hits.size());
  122. for (int i = 0; i < object_hits.size(); i++) {
  123. object_hits[i] += state->object_hits[i];
  124. }
  125. }
  126. uint64_t Profiler::get_event(ProfilingEvent event)
  127. {
  128. assert(worker == NULL);
  129. return event_samples[event];
  130. }
  131. bool Profiler::get_shader(int shader, uint64_t &samples, uint64_t &hits)
  132. {
  133. assert(worker == NULL);
  134. if (shader_samples[shader] == 0) {
  135. return false;
  136. }
  137. samples = shader_samples[shader];
  138. hits = shader_hits[shader];
  139. return true;
  140. }
  141. bool Profiler::get_object(int object, uint64_t &samples, uint64_t &hits)
  142. {
  143. assert(worker == NULL);
  144. if (object_samples[object] == 0) {
  145. return false;
  146. }
  147. samples = object_samples[object];
  148. hits = object_hits[object];
  149. return true;
  150. }
  151. CCL_NAMESPACE_END