comp-imaging / ProxImaL

A domain-specific language for image optimization.
MIT License
112 stars 29 forks source link

Anderson2021 autoscheduler triggers "producer_store_instances > 0" #93

Open antonysigma opened 10 months ago

antonysigma commented 10 months ago

Working draft for debugging purpose: https://github.com/antonysigma/proximal/tree/debug-producer-error

Observations: when we define the Halide Func and then return them as std::tuple, the generator can capture the algorithm pipeline and schedule it with Mullapudi2016 autoscheduler. But not Anderson2021. The autoscheduler reports:

Unhandled exception: Internal Error at .../autoschedulers/anderson2021/LoopNest.cpp:2747
triggered by user code at :
Condition failed: producer_store_instances > 0:

The same assertion failure happens with C++ structured bindings, as well as passing return values as function reference.

The offending line is shown below:

using Halide::Func
template<size_t N> using FuncTuple = std::array<Func, N>;
std::vector<Func> v_list(n_iter);
std::vector<FuncTuple<psi_size>> z_list(n_iter);
std::vector<FuncTuple<psi_size>> u_list(n_iter);

for (size_t i = 0; i < n_iter; i++) {
    std::tie(v_list[i], z_list[i], u_list[i]) = algorithm::linearized_admm::iterate(
        v, z_prev, u_prev, K, omega_fn, psi_fns, lmb, mu, input);
}

See also: #67 .

antonysigma commented 10 months ago

Note to self: the Anderson2021-specific assertion failure producer_store_instances > 0 is eliminated when the returned Func, captured via structured binding, is in-turn copied to the target Func via the elementwise operation. Copy assignment operator doesn't work.

In other words, the following code triggers assertion failure:

std::tie(v_list[i], z_list[i], u_list[i])
    = algorithm::linearized_admm::iterate(
    v, z_prev, u_prev, K, omega_fn, psi_fns, lmb, mu, input);

This too:

const auto [_v_new, z_new, u_new]
    = algorithm::linearized_admm::iterate(
    v, z_prev, u_prev, K, omega_fn, psi_fns, lmb, mu, input);

v_list[i] = _v_new;
z_list[i] = z_new;
u_list[i] = u_new;

And this works:

const auto [_v_new, z_new, u_new]
    = algorithm::linearized_admm::iterate(
    v, z_prev, u_prev, K, omega_fn, psi_fns, lmb, mu, input);

using Halide::_;
v_list[i](x, y, c, _) = _v_new(x, y, c, _);

std::copy(u_new.begin(), u_new.end(), u_list[i].begin());

std::transform(z_new.begin(), z_new.end(), z_list[i].begin(), [](const auto& _z) -> Func{
    Func _z_new;
    _z_new(x, y, c, _) = _z(x, y, c, _);
    return _z_new;
});
antonysigma commented 10 months ago

Hi @aekul,

Just curious, what does Condition failed: producer_store_instances > 0 do in the autoscheduler? I am using C++17's structured binding syntax to capture Functions as std::tuple, but the Anderson2021 auto-scheduler doesn't seem to like it.

https://github.com/halide/Halide/blob/186510173d4a9f344ef365e2ccc334e90aacec41/src/autoschedulers/anderson2021/LoopNest.cpp#L2742-L2747

Comparing the code between Anderson2021 and Adams2019, the key difference is in the condition producer_has_been_scheduled. What does it do? And, how do I get started to debug my code?

aekul commented 9 months ago

producer_store_instances should be the number of times the producer is allocated e.g. if the producer is stored at root, then it will be allocated once so producer_store_instances will be 1. I would expect it to always be >= 1 (assuming that the value has actually been computed already) since there must be at least 1 allocation, so I think that's what the assert is checking.

I haven't had a chance to look too closely and don't recall all the details but producer_has_been_scheduled is true for inputs and when site.produce != nullptr (we know the loop nest where it will be produced). It sounds like the producer's featurization has not been computed for some reason.

For debugging, it would be useful to know whether producer_has_been_scheduled is true and which stage the producer is. You could then try to see if that stage does in fact have its featurization computed or not. If you can reduce this to a more minimal example, I can potentially take a closer look too.

antonysigma commented 9 months ago

Thanks @aekul for the guidance. I will start by printing the current stage and the input stage names -- just to identify the halide Stage causing the assertion failure. It should help me further reduce the repo code size for further debugging purposes.

antonysigma commented 9 months ago

Note to self: producer_has_been_scheduled is false at the following expression. Consumer = u_new$1, producer = _z. site.produce is nullptr. I will continue to debug...

https://github.com/comp-imaging/ProxImaL/blob/4ba04596a359620b103c7ff2dea6b4a783eda8f9/proximal/halide/src/algorithm/linearized-admm.h#L100-L109