in source/Interprocedural.cpp [173:269]
void Interprocedural::run_analysis(Context& context, Registry& registry) {
LOG(1, "Computing global fixpoint...");
auto methods_to_analyze = std::make_unique<ConcurrentSet<const Method*>>();
for (const auto* method : *context.methods) {
methods_to_analyze->insert(method);
}
std::size_t iteration = 0;
while (methods_to_analyze->size() > 0) {
Timer iteration_timer;
iteration++;
auto resident_set_size = resident_set_size_in_gb();
context.statistics->log_resident_set_size(resident_set_size);
LOG(1,
"Global iteration {}. Analyzing {} methods... (Memory used, RSS: {:.2f}GB)",
iteration,
methods_to_analyze->size(),
resident_set_size);
if (iteration > Heuristics::kMaxNumberIterations) {
ERROR(1, "Too many iterations");
std::string message = "Unstable methods are:";
for (const auto* method : *methods_to_analyze) {
message.append(fmt::format("\n`{}`", method->show()));
}
LOG(1, message);
throw std::runtime_error("Too many iterations, exiting.");
}
auto new_methods_to_analyze =
std::make_unique<ConcurrentSet<const Method*>>();
unsigned int threads = sparta::parallel::default_num_threads();
if (context.options->sequential()) {
WARNING(1, "Running sequentially!");
threads = 1u;
}
std::atomic<std::size_t> method_iteration(0);
auto queue = sparta::work_queue<const Method*>(
[&](const Method* method) {
method_iteration++;
if (method_iteration % 10000 == 0) {
LOG(1,
"Processed {}/{} methods.",
method_iteration.load(),
methods_to_analyze->size());
} else if (method_iteration % 100 == 0) {
LOG(4,
"Processed {}/{} methods.",
method_iteration.load(),
methods_to_analyze->size());
}
const auto old_model = registry.get(method);
if (old_model.skip_analysis()) {
LOG(3, "Skipping `{}`...", method->show());
return;
}
auto new_model = analyze(context, registry, old_model);
new_model.join_with(old_model);
if (!new_model.leq(old_model)) {
if (!context.call_graph->callees(method).empty() ||
!context.call_graph->artificial_callees(method).empty()) {
new_methods_to_analyze->insert(method);
}
for (const auto* dependency :
context.dependencies->dependencies(method)) {
new_methods_to_analyze->insert(dependency);
}
}
registry.set(new_model);
},
threads);
context.scheduler->schedule(
*methods_to_analyze,
[&](const Method* method, std::size_t worker_id) {
queue.add_item(method, worker_id);
},
threads);
queue.run_all();
LOG(2,
"Global fixpoint iteration completed in {:.2f}s.",
iteration_timer.duration_in_seconds());
methods_to_analyze = std::move(new_methods_to_analyze);
}
context.statistics->log_number_iterations(iteration);
LOG(2, "Global fixpoint reached.");
}