Skip to content

Commit d474859

Browse files
Added mapping from pointer to variable for debugging
1 parent 3a33b55 commit d474859

File tree

5 files changed

+81
-21
lines changed

5 files changed

+81
-21
lines changed

src/eval.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -817,6 +817,10 @@ void jitc_eval_impl(ThreadState *ts) {
817817

818818
if (v->is_array())
819819
v->scope = 0;
820+
821+
#ifndef NDEBUG
822+
state.ptr_to_variable.insert({ v->data, index });
823+
#endif
820824
}
821825

822826
uint32_t dep[4], side_effect = v->side_effect;

src/internal.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -840,6 +840,8 @@ struct KernelHistory {
840840

841841
using UnusedPQ = std::priority_queue<uint32_t, std::vector<uint32_t>, std::greater<uint32_t>>;
842842

843+
using PointerMap = tsl::robin_map<const void *, uint32_t, PointerHasher>;
844+
843845
/// Records the full JIT compiler state (most frequently two used entries at top)
844846
struct State {
845847
/// Must be held to access members of this data structure
@@ -927,6 +929,13 @@ struct State {
927929
uint32_t optix_default_sbt_index = 0;
928930
#endif
929931

932+
#ifndef NDEBUG
933+
/// Mapping from pointers that are managed by variables to their variable
934+
/// indices. This is used for debugging purposes in frozen functions.
935+
PointerMap ptr_to_variable;
936+
#endif
937+
938+
930939
State() {
931940
variables.resize(1);
932941
extra.resize(1);

src/record_ts.cpp

Lines changed: 47 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -2034,34 +2034,46 @@ void RecordThreadState::enqueue_host_func(void (*callback)(void *),
20342034
(void) callback; (void) payload;
20352035
}
20362036

2037-
void Recording::validate() {
2037+
void Recording::validate(uint32_t scope) {
20382038
for (uint32_t i = 0; i < recorded_variables.size(); i++) {
20392039
RecordedVariable &rv = recorded_variables[i];
20402040
if (rv.state == RecordedVarState::Uninitialized) {
20412041
Operation &last_op = operations[rv.last_op];
20422042
#ifndef NDEBUG
2043+
uint32_t index = 0;
2044+
const char *scope_string = "before";
2045+
auto it = state.ptr_to_variable.find(rv.ptr);
2046+
if (it != state.ptr_to_variable.end()) {
2047+
index = it->second;
2048+
Variable *var = jitc_var(index);
2049+
if (var->scope >= scope)
2050+
scope_string = "inside";
2051+
}
20432052
if (last_op.type == OpType::Aggregate) {
20442053
jitc_raise(
20452054
"validate(): The frozen function included a virtual "
2046-
"function call involving variable s%u <%p>, last used by "
2047-
"operation o%u. Dr.Jit would normally traverse a registry "
2048-
"of all relevant object instances in order to collect "
2049-
"their member variables. However, when recording this "
2050-
"frozen function, this traversal was skipped because no "
2051-
"such object instance was found in the function's inputs. "
2052-
"You can trigger traversal by including the relevant "
2053-
"objects in the function input, or by specifying them "
2054-
"using the state_fn argument. Alternatively, this error "
2055-
"might be caused by a nested "
2055+
"function call involving Variable r%u at slot s%u <%p>"
2056+
"which created %s the frozen function and was last used by "
2057+
"operation o%u. Dr.Jit would "
2058+
"normally traverse a registry of all relevant object "
2059+
"instances in order to collect their member variables. "
2060+
"However, when recording this frozen function, this "
2061+
"traversal was skipped because no such object instance was "
2062+
"found in the function's inputs. You can trigger traversal "
2063+
"by including the relevant objects in the function input, "
2064+
"or by specifying them using the state_fn argument. "
2065+
"Alternatively, this error might be caused by a nested "
20562066
"virtual function call.",
2057-
i, rv.ptr, rv.last_op);
2067+
index, i, rv.ptr, scope_string, rv.last_op);
20582068
} else
20592069
jitc_raise(
2060-
"validate(): Variable at slot s%u <%p> was used by %s operation "
2061-
"o%u but left in an uninitialized state! This indicates "
2062-
"that the associated variable was used, but not traversed "
2063-
"as part of the frozen function input.",
2064-
i, rv.ptr, op_type_name[(uint32_t) last_op.type], rv.last_op);
2070+
"validate(): Variable r%u at slot s%u <%p> which was "
2071+
"created %s the frozen function and was last used by %s "
2072+
"operation o%u but left in an uninitialized state! This "
2073+
"indicates that the associated variable was used, but not "
2074+
"traversed as part of the frozen function input.",
2075+
index, i, rv.ptr, scope_string,
2076+
op_type_name[(uint32_t) last_op.type], rv.last_op);
20652077
#else
20662078
if (last_op.type == OpType::Aggregate) {
20672079
jitc_raise(
@@ -2301,14 +2313,29 @@ void RecordThreadState::add_param(AccessInfo info) {
23012313
jitc_log(LogLevel::Debug, " -> param s%u", info.slot);
23022314

23032315
RecordedVariable &rv = m_recording.recorded_variables[info.slot];
2304-
if (info.test_uninit && rv.state == RecordedVarState::Uninitialized)
2316+
if (info.test_uninit && rv.state == RecordedVarState::Uninitialized){
2317+
#ifndef NDEBUG
2318+
uint32_t index = 0;
2319+
auto it = state.ptr_to_variable.find(rv.ptr);
2320+
if (it != state.ptr_to_variable.end())
2321+
index = it->second;
2322+
jitc_raise("record(): Variable r%u at slot s%u was read by "
2323+
"operation o%u, but it had not yet been initialized! "
2324+
"This can occur if the variable was not part of "
2325+
"the input but is used by a recorded operation, for "
2326+
"example if it was not specified as a member in a "
2327+
"DRJIT_STRUCT but used in the frozen function.",
2328+
index, info.slot, (uint32_t) m_recording.operations.size());
2329+
#else
23052330
jitc_raise("record(): Variable at slot s%u was read by "
23062331
"operation o%u, but it had not yet been initialized! "
23072332
"This can occur if the variable was not part of "
23082333
"the input but is used by a recorded operation, for "
23092334
"example if it was not specified as a member in a "
23102335
"DRJIT_STRUCT but used in the frozen function.",
23112336
info.slot, (uint32_t) m_recording.operations.size());
2337+
#endif
2338+
}
23122339

23132340
if (info.vtype == VarType::Void)
23142341
info.vtype = rv.type;
@@ -2544,6 +2571,7 @@ Recording *jitc_freeze_stop(JitBackend backend, const uint32_t *outputs,
25442571
dynamic_cast<RecordThreadState *>(thread_state(backend));
25452572
rts != nullptr) {
25462573
ThreadState *internal = rts->m_internal;
2574+
uint32_t scope = internal->scope;
25472575

25482576
// Perform reassignments to internal thread-state of possibly changed
25492577
// variables
@@ -2571,7 +2599,7 @@ Recording *jitc_freeze_stop(JitBackend backend, const uint32_t *outputs,
25712599
}
25722600
Recording *recording = new Recording(std::move(rts->m_recording));
25732601
try{
2574-
recording->validate();
2602+
recording->validate(scope);
25752603
} catch (const std::exception &) {
25762604
recording->destroy();
25772605
throw;

src/record_ts.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -321,7 +321,7 @@ struct Recording {
321321

322322
/// This function is called after recording and checks that the recording is
323323
/// valid i.e. that no variables where left uninitialized.
324-
void validate();
324+
void validate(uint32_t scope);
325325
/// Checks if all recorded kernels are still in the kernel cache. This might
326326
/// occur when calling dr.kernel_cache_flush between recording the function
327327
/// and replaying it.

src/var.cpp

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -309,8 +309,22 @@ JIT_NOINLINE void jitc_var_free(uint32_t index, Variable *v) noexcept {
309309

310310
if (v->is_evaluated()) {
311311
// Release memory referenced by this variable
312-
if (!v->retain_data)
312+
if (!v->retain_data) {
313313
jitc_free(v->data);
314+
315+
#ifndef NDEBUG
316+
// This warning should never be thrown, except if we forgot to
317+
// populate the mapping
318+
if (!state.ptr_to_variable.contains(v->data))
319+
jitc_log(
320+
LogLevel::Warn,
321+
"Pointr <%p> was mangaged by variable r%u, but this "
322+
"was not recorded in the pointer to variable map!",
323+
v->data, index);
324+
325+
state.ptr_to_variable.erase(v->data);
326+
#endif
327+
}
314328
} else {
315329
// Unevaluated variable, drop from CSE cache
316330
jitc_lvn_drop(index, v);
@@ -784,6 +798,11 @@ uint32_t jitc_var_new(Variable &v, bool disable_lvn) {
784798
jitc_sanitation_checkpoint();
785799
#endif
786800

801+
#ifndef NDEBUG
802+
if (v.is_evaluated())
803+
state.ptr_to_variable.insert({ v.data, index });
804+
#endif
805+
787806
return index;
788807
}
789808

0 commit comments

Comments
 (0)