Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Silence Adams2019 Autoscheduler #6854

Merged
merged 11 commits into from
Jul 15, 2022
7 changes: 7 additions & 0 deletions src/autoschedulers/adams2019/ASLog.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
// libHalide, so (despite the namespace) we are better off not
// including Halide.h, lest we reference something we won't have available

#include <cassert>
#include <cstdlib>
#include <iostream>
#include <utility>
Expand All @@ -28,6 +29,12 @@ class aslog {
return *this;
}

std::ostream &get_ostream() {
// It is an error to call this for an aslog() instance that cannot log.
assert(logging);
return std::cerr;
}

static int aslog_level();
};

Expand Down
77 changes: 41 additions & 36 deletions src/autoschedulers/adams2019/AutoSchedule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -117,42 +117,45 @@ struct ProgressBar {
if (!draw_progress_bar) {
return;
}
auto &os = aslog(ProgressBarLogLevel).get_ostream();
counter++;
const int bits = 11;
if (counter & ((1 << bits) - 1)) {
return;
}
const int pos = (int)(progress * 78);
aslog(0) << "[";
os << "[";
for (int j = 0; j < 78; j++) {
if (j < pos) {
aslog(0) << ".";
os << ".";
} else if (j - 1 < pos) {
aslog(0) << "/-\\|"[(counter >> bits) % 4];
os << "/-\\|"[(counter >> bits) % 4];
} else {
aslog(0) << " ";
os << " ";
}
}
aslog(0) << "]";
os << "]";
for (int j = 0; j < 80; j++) {
aslog(0) << "\b";
os << "\b";
}
}

void clear() {
if (counter) {
auto &os = aslog(ProgressBarLogLevel).get_ostream();
for (int j = 0; j < 80; j++) {
aslog(0) << " ";
os << " ";
}
for (int j = 0; j < 80; j++) {
aslog(0) << "\b";
os << "\b";
}
}
}

private:
uint32_t counter = 0;
const bool draw_progress_bar = isatty(2);
static constexpr int ProgressBarLogLevel = 1;
const bool draw_progress_bar = isatty(2) && aslog::aslog_level() >= ProgressBarLogLevel;
};

// Get the HL_RANDOM_DROPOUT environment variable. Purpose of this is described above.
Expand Down Expand Up @@ -290,10 +293,6 @@ IntrusivePtr<State> optimal_schedule_pass(FunctionDAG &dag,

std::function<void(IntrusivePtr<State> &&)> enqueue_new_children =
[&](IntrusivePtr<State> &&s) {
// aslog(0) << "\n** Generated child: ";
// s->dump();
// s->calculate_cost(dag, params, nullptr, true);

// Each child should have one more decision made than its parent state.
internal_assert(s->num_decisions_made == s->parent->num_decisions_made + 1);

Expand Down Expand Up @@ -338,7 +337,7 @@ IntrusivePtr<State> optimal_schedule_pass(FunctionDAG &dag,
}

if ((int)pending.size() > beam_size * 10000) {
aslog(0) << "Warning: Huge number of states generated (" << pending.size() << ").\n";
aslog(1) << "*** Warning: Huge number of states generated (" << pending.size() << ").\n";
}

expanded = 0;
Expand Down Expand Up @@ -436,25 +435,26 @@ IntrusivePtr<State> optimal_schedule_pass(FunctionDAG &dag,
// The user has set HL_CYOS, and wants to navigate the
// search space manually. Discard everything in the queue
// except for the user-chosen option.
aslog(0) << "\n--------------------\n";
aslog(0) << "Select a schedule:\n";
std::cout << "\n--------------------\n";
std::cout << "Select a schedule:\n";
for (int choice_label = (int)q.size() - 1; choice_label >= 0; choice_label--) {
auto state = q[choice_label];
aslog(0) << "\n[" << choice_label << "]:\n";
state->dump();
state->calculate_cost(dag, params, cost_model, cache->options, memory_limit, true);
std::cout << "\n[" << choice_label << "]:\n";
state->dump(std::cout);
constexpr int verbosity_level = 0; // always
state->calculate_cost(dag, params, cost_model, cache->options, memory_limit, verbosity_level);
}
cost_model->evaluate_costs();

// Select next partial schedule to expand.
int selection = -1;
while (selection < 0 || selection >= (int)q.size()) {
aslog(0) << "\nEnter selection: ";
std::cout << "\nEnter selection: ";
std::cin >> selection;
}

auto selected = q[selection];
selected->dump();
selected->dump(std::cout);
q.clear();
q.emplace(std::move(selected));
}
Expand Down Expand Up @@ -508,11 +508,16 @@ IntrusivePtr<State> optimal_schedule(FunctionDAG &dag,

tick.clear();

if (aslog::aslog_level() == 0) {
aslog(0) << "Pass " << i << " of " << num_passes << ", cost: " << pass->cost << ", time (ms): " << milli << "\n";
} else {
aslog(0) << "Pass " << i << " result: ";
pass->dump();
switch (aslog::aslog_level()) {
case 0:
// Silence
break;
case 1:
aslog(1) << "Pass " << i << " of " << num_passes << ", cost: " << pass->cost << ", time (ms): " << milli << "\n";
break;
default:
aslog(2) << "Pass " << i << " result: ";
pass->dump(aslog(2).get_ostream());
}

if (i == 0 || pass->cost < best->cost) {
Expand All @@ -522,11 +527,11 @@ IntrusivePtr<State> optimal_schedule(FunctionDAG &dag,
}
}

aslog(0) << "Best cost: " << best->cost << "\n";
aslog(1) << "Best cost: " << best->cost << "\n";

if (options.cache_blocks) {
aslog(0) << "Cache (block) hits: " << cache.cache_hits << "\n";
aslog(0) << "Cache (block) misses: " << cache.cache_misses << "\n";
aslog(1) << "Cache (block) hits: " << cache.cache_hits << "\n";
aslog(1) << "Cache (block) misses: " << cache.cache_misses << "\n";
}

return best;
Expand All @@ -540,7 +545,7 @@ void generate_schedule(const std::vector<Function> &outputs,
const Target &target,
const MachineParams &params,
AutoSchedulerResults *auto_scheduler_results) {
aslog(0) << "generate_schedule for target=" << target.to_string() << "\n";
aslog(1) << "generate_schedule for target=" << target.to_string() << "\n";

// Start a timer
HALIDE_TIC;
Expand All @@ -554,7 +559,7 @@ void generate_schedule(const std::vector<Function> &outputs,
if (!seed_str.empty()) {
seed = atoi(seed_str.c_str());
}
aslog(1) << "Dropout seed = " << seed << "\n";
aslog(2) << "Dropout seed = " << seed << "\n";
std::mt19937 rng((uint32_t)seed);

// Get the beam size
Expand All @@ -576,8 +581,8 @@ void generate_schedule(const std::vector<Function> &outputs,

// Analyse the Halide algorithm and construct our abstract representation of it
FunctionDAG dag(outputs, params, target);
if (aslog::aslog_level() > 0) {
dag.dump();
if (aslog::aslog_level() >= 2) {
dag.dump(aslog(2).get_ostream());
}

// Construct a cost model to use to evaluate states. Currently we
Expand All @@ -602,14 +607,14 @@ void generate_schedule(const std::vector<Function> &outputs,
aslog(1) << "** Optimal schedule:\n";

// Just to get the debugging prints to fire
optimal->calculate_cost(dag, params, cost_model.get(), cache_options, memory_limit, aslog::aslog_level() > 0);
optimal->calculate_cost(dag, params, cost_model.get(), cache_options, memory_limit, /*verbosity_level*/ 1);

// Apply the schedules to the pipeline
optimal->apply_schedule(dag, params);

// Print out the schedule
if (aslog::aslog_level() > 0) {
optimal->dump();
if (aslog::aslog_level() >= 2) {
optimal->dump(aslog(2).get_ostream());
}

string schedule_file = get_env_variable("HL_SCHEDULE_FILE");
Expand Down
14 changes: 7 additions & 7 deletions src/autoschedulers/adams2019/DefaultCostModel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -232,18 +232,18 @@ float DefaultCostModel::backprop(const Runtime::Buffer<const float> &true_runtim
*(cost_ptrs(i)) = dst(i);
if (std::isnan(dst(i))) {
any_nans = true;
aslog(0) << "Prediction " << i << " is NaN. True runtime is " << true_runtimes(i) << "\n";
aslog(0) << "Checking pipeline features for NaNs...\n";
aslog(1) << "Prediction " << i << " is NaN. True runtime is " << true_runtimes(i) << "\n";
aslog(1) << "Checking pipeline features for NaNs...\n";
pipeline_feat_queue.for_each_value([&](float f) { if (std::isnan(f)) abort(); });
aslog(0) << "None found\n";
aslog(0) << "Checking schedule features for NaNs...\n";
aslog(1) << "None found\n";
aslog(1) << "Checking schedule features for NaNs...\n";
schedule_feat_queue.for_each_value([&](float f) { if (std::isnan(f)) abort(); });
aslog(0) << "None found\n";
aslog(0) << "Checking network weights for NaNs...\n";
aslog(1) << "None found\n";
aslog(1) << "Checking network weights for NaNs...\n";
weights.for_each_buffer([&](const Runtime::Buffer<float> &buf) {
buf.for_each_value([&](float f) { if (std::isnan(f)) abort(); });
});
aslog(0) << "None found\n";
aslog(1) << "None found\n";
}
internal_assert(true_runtimes(i) > 0);
}
Expand Down
14 changes: 2 additions & 12 deletions src/autoschedulers/adams2019/Featurization.h
Original file line number Diff line number Diff line change
Expand Up @@ -99,8 +99,7 @@ struct PipelineFeatures {
// Each row sums to 1 or 0. Each column sums to 1. f(z, y, x, 4)
int slice_accesses[(int)AccessType::NumAccessTypes][(int)ScalarType::NumScalarTypes] = {};

template<typename OS>
void dump(OS &os) const {
void dump(std::ostream &os) const {
for (int i = 0; i < (int)ScalarType::NumScalarTypes; i++) {
const char *type_names[] = {"Bool", "UInt8", "UInt16", "UInt32", "UInt64", "Float", "Double"};
// Skip printing for types not used
Expand Down Expand Up @@ -157,10 +156,6 @@ struct PipelineFeatures {
<< slice_accesses[3][i] << "\n";
}
}
void dump() const {
auto os = aslog(0);
dump(os);
}
};

// The schedule-dependent portion of the featurization of a stage
Expand Down Expand Up @@ -314,8 +309,7 @@ struct ScheduleFeatures {
double working_set_at_realization = 0;
double working_set_at_root = 0;

template<typename OS>
void dump(OS &os) const {
void dump(std::ostream &os) const {
os << " num_realizations: " << num_realizations << "\n"
<< " num_productions: " << num_productions << "\n"
<< " points_computed_per_realization: " << points_computed_per_realization << "\n"
Expand Down Expand Up @@ -356,10 +350,6 @@ struct ScheduleFeatures {
<< " working_set_at_realization: " << working_set_at_realization << "\n"
<< " working_set_at_root: " << working_set_at_root << "\n";
}
void dump() const {
auto os = aslog(0);
dump(os);
}

bool equal(const ScheduleFeatures &other) const {
const size_t n_features = ScheduleFeatures::num_features();
Expand Down
43 changes: 17 additions & 26 deletions src/autoschedulers/adams2019/FunctionDAG.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -307,42 +307,44 @@ class Featurizer : public IRVisitor {

} // namespace

void LoadJacobian::dump(const char *prefix) const {
void LoadJacobian::dump(std::ostream &os, const char *prefix) const {
if (count() > 1) {
aslog(0) << prefix << count() << " x\n";
os << prefix << count() << " x\n";
}
for (size_t i = 0; i < producer_storage_dims(); i++) {
aslog(0) << prefix << " [";
os << prefix << " [";

for (size_t j = 0; j < consumer_loop_dims(); j++) {
const auto &c = (*this)(i, j);
if (!c.exists) {
aslog(0) << " _ ";
os << " _ ";
} else if (c.denominator == 1) {
aslog(0) << " " << c.numerator << " ";
os << " " << c.numerator << " ";
} else {
aslog(0) << c.numerator << "/" << c.denominator << " ";
os << c.numerator << "/" << c.denominator << " ";
}
}
aslog(0) << "]\n";
os << "]\n";
}
aslog(0) << "\n";
os << "\n";
}

void BoundContents::validate() const {
for (int i = 0; i < layout->total_size; i++) {
auto p = data()[i];
if (p.max() < p.min()) {
aslog(0) << "Bad bounds object:\n";
std::ostringstream err;
err << "Bad bounds object:\n";
for (int j = 0; j < layout->total_size; j++) {
if (i == j) {
aslog(0) << "=> ";
err << "=> ";
} else {
aslog(0) << " ";
err << " ";
}
aslog(0) << j << ": " << data()[j].min() << ", " << data()[j].max() << "\n";
err << j << ": " << data()[j].min() << ", " << data()[j].max() << "\n";
}
internal_error << "Aborting";
err << "Aborting";
internal_error << err.str();
}
}
}
Expand Down Expand Up @@ -1039,8 +1041,7 @@ void FunctionDAG::featurize() {
}
}

template<typename OS>
void FunctionDAG::dump_internal(OS &os) const {
void FunctionDAG::dump(std::ostream &os) const {
for (const Node &n : nodes) {
os << "Node: " << n.func.name() << "\n"
<< " Symbolic region required: \n";
Expand Down Expand Up @@ -1076,21 +1077,11 @@ void FunctionDAG::dump_internal(OS &os) const {

os << " Load Jacobians:\n";
for (const auto &jac : e.load_jacobians) {
jac.dump(" ");
jac.dump(os, " ");
}
}
}

void FunctionDAG::dump() const {
auto os = aslog(0);
dump_internal(os);
}

std::ostream &FunctionDAG::dump(std::ostream &os) const {
dump_internal(os);
return os;
}

} // namespace Autoscheduler
} // namespace Internal
} // namespace Halide
8 changes: 2 additions & 6 deletions src/autoschedulers/adams2019/FunctionDAG.h
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,7 @@ class LoadJacobian {
return result;
}

void dump(const char *prefix) const;
void dump(std::ostream &os, const char *prefix) const;
};

// Classes to represent a concrete set of bounds for a Func. A Span is
Expand Down Expand Up @@ -565,16 +565,12 @@ struct FunctionDAG {
// analysis. This is done once up-front before the tree search.
FunctionDAG(const vector<Function> &outputs, const MachineParams &params, const Target &target);

void dump() const;
std::ostream &dump(std::ostream &os) const;
void dump(std::ostream &os) const;

private:
// Compute the featurization for the entire DAG
void featurize();

template<typename OS>
void dump_internal(OS &os) const;

public:
// This class uses a lot of internal pointers, so we'll make it uncopyable/unmovable.
FunctionDAG(const FunctionDAG &other) = delete;
Expand Down
Loading