blender/intern/cycles/util/util_profiling.h

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

175 lines
4.5 KiB
C
Raw Normal View History

/*
* Copyright 2011-2018 Blender Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __UTIL_PROFILING_H__
#define __UTIL_PROFILING_H__
#include <atomic>
#include "util/util_map.h"
#include "util/util_thread.h"
#include "util/util_vector.h"
CCL_NAMESPACE_BEGIN
enum ProfilingEvent : uint32_t {
PROFILING_UNKNOWN,
PROFILING_RAY_SETUP,
PROFILING_PATH_INTEGRATE,
PROFILING_SCENE_INTERSECT,
PROFILING_INDIRECT_EMISSION,
PROFILING_VOLUME,
PROFILING_SHADER_SETUP,
PROFILING_SHADER_EVAL,
PROFILING_SHADER_APPLY,
PROFILING_AO,
PROFILING_SUBSURFACE,
PROFILING_CONNECT_LIGHT,
PROFILING_SURFACE_BOUNCE,
PROFILING_WRITE_RESULT,
PROFILING_INTERSECT,
PROFILING_INTERSECT_LOCAL,
PROFILING_INTERSECT_SHADOW_ALL,
PROFILING_INTERSECT_VOLUME,
PROFILING_INTERSECT_VOLUME_ALL,
PROFILING_CLOSURE_EVAL,
PROFILING_CLOSURE_SAMPLE,
PROFILING_CLOSURE_VOLUME_EVAL,
PROFILING_CLOSURE_VOLUME_SAMPLE,
PROFILING_DENOISING,
PROFILING_DENOISING_CONSTRUCT_TRANSFORM,
PROFILING_DENOISING_RECONSTRUCT,
PROFILING_DENOISING_DIVIDE_SHADOW,
PROFILING_DENOISING_NON_LOCAL_MEANS,
PROFILING_DENOISING_COMBINE_HALVES,
PROFILING_DENOISING_GET_FEATURE,
PROFILING_DENOISING_DETECT_OUTLIERS,
PROFILING_NUM_EVENTS,
};
/* Contains the current execution state of a worker thread.
* These values are constantly updated by the worker.
* Periodically the profiler thread will wake up, read them
* and update its internal counters based on it.
*
* Atomics aren't needed here since we're only doing direct
* writes and reads to (4-byte-aligned) uint32_t, which is
* guaranteed to be atomic on x86 since the 486.
* Memory ordering is not guaranteed but does not matter.
*
* And even on other architectures, the extremely rare corner
* case of reading an intermediate state could at worst result
* in a single incorrect sample. */
struct ProfilingState {
volatile uint32_t event = PROFILING_UNKNOWN;
volatile int32_t shader = -1;
volatile int32_t object = -1;
volatile bool active = false;
vector<uint64_t> shader_hits;
vector<uint64_t> object_hits;
};
class Profiler {
public:
Profiler();
~Profiler();
void reset(int num_shaders, int num_objects);
void start();
void stop();
void add_state(ProfilingState *state);
void remove_state(ProfilingState *state);
uint64_t get_event(ProfilingEvent event);
bool get_shader(int shader, uint64_t &samples, uint64_t &hits);
bool get_object(int object, uint64_t &samples, uint64_t &hits);
protected:
void run();
/* Tracks how often the worker was in each ProfilingEvent while sampling,
* so multiplying the values by the sample frequency (currently 1ms)
* gives the approximate time spent in each state. */
vector<uint64_t> event_samples;
vector<uint64_t> shader_samples;
vector<uint64_t> object_samples;
/* Tracks the total amounts every object/shader was hit.
* Used to evaluate relative cost, written by the render thread.
* Indexed by the shader and object IDs that the kernel also uses
* to index __object_flag and __shaders. */
vector<uint64_t> shader_hits;
vector<uint64_t> object_hits;
volatile bool do_stop_worker;
thread *worker;
thread_mutex mutex;
vector<ProfilingState *> states;
};
class ProfilingHelper {
public:
ProfilingHelper(ProfilingState *state, ProfilingEvent event) : state(state)
{
previous_event = state->event;
state->event = event;
}
inline void set_event(ProfilingEvent event)
{
state->event = event;
}
inline void set_shader(int shader)
{
state->shader = shader;
if (state->active) {
assert(shader < state->shader_hits.size());
state->shader_hits[shader]++;
}
}
inline void set_object(int object)
{
state->object = object;
if (state->active) {
assert(object < state->object_hits.size());
state->object_hits[object]++;
}
}
~ProfilingHelper()
{
state->event = previous_event;
}
private:
ProfilingState *state;
uint32_t previous_event;
};
CCL_NAMESPACE_END
#endif /* __UTIL_PROFILING_H__ */