llvm-project/flang-rt/lib/runtime/work-queue.cpp
Peter Klausler 2e53a68c09
[flang][runtime] Speed up initialization & destruction (#148087)
Rework derived type initialization in the runtime to just initialize the
first element of any array, and then memcpy it to the others, rather
than exercising the per-component paths for each element.

Reword derived type destruction in the runtime to detect and exploit a
fast path for allocatable components whose types themselves don't need
nested destruction.

Small tweaks were made in hot paths exposed by profiling in descriptor
operations and derived type assignment.
2025-07-14 11:14:02 -07:00

150 lines
3.9 KiB
C++

//===-- lib/runtime/work-queue.cpp ------------------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include "flang-rt/runtime/work-queue.h"
#include "flang-rt/runtime/environment.h"
#include "flang-rt/runtime/memory.h"
#include "flang-rt/runtime/type-info.h"
#include "flang/Common/visit.h"
namespace Fortran::runtime {
#if !defined(RT_DEVICE_COMPILATION)
// FLANG_RT_DEBUG code is disabled when false.
static constexpr bool enableDebugOutput{false};
#endif
RT_OFFLOAD_API_GROUP_BEGIN
RT_API_ATTRS int Ticket::Continue(WorkQueue &workQueue) {
if (!begun) {
begun = true;
return common::visit(
[&workQueue](
auto &specificTicket) { return specificTicket.Begin(workQueue); },
u);
} else {
return common::visit(
[&workQueue](auto &specificTicket) {
return specificTicket.Continue(workQueue);
},
u);
}
}
RT_API_ATTRS WorkQueue::~WorkQueue() {
if (anyDynamicAllocation_) {
if (last_) {
if ((last_->next = firstFree_)) {
last_->next->previous = last_;
}
firstFree_ = first_;
first_ = last_ = nullptr;
}
while (firstFree_) {
TicketList *next{firstFree_->next};
if (!firstFree_->isStatic) {
FreeMemory(firstFree_);
}
firstFree_ = next;
}
}
}
RT_API_ATTRS Ticket &WorkQueue::StartTicket() {
if (!firstFree_) {
void *p{AllocateMemoryOrCrash(terminator_, sizeof(TicketList))};
firstFree_ = new (p) TicketList;
firstFree_->isStatic = false;
anyDynamicAllocation_ = true;
}
TicketList *newTicket{firstFree_};
if ((firstFree_ = newTicket->next)) {
firstFree_->previous = nullptr;
}
TicketList *after{insertAfter_ ? insertAfter_->next : nullptr};
if ((newTicket->previous = insertAfter_ ? insertAfter_ : last_)) {
newTicket->previous->next = newTicket;
} else {
first_ = newTicket;
}
if ((newTicket->next = after)) {
after->previous = newTicket;
} else {
last_ = newTicket;
}
newTicket->ticket.begun = false;
#if !defined(RT_DEVICE_COMPILATION)
if (enableDebugOutput &&
(executionEnvironment.internalDebugging &
ExecutionEnvironment::WorkQueue)) {
std::fprintf(stderr, "WQ: new ticket\n");
}
#endif
return newTicket->ticket;
}
RT_API_ATTRS int WorkQueue::Run() {
while (last_) {
TicketList *at{last_};
insertAfter_ = last_;
#if !defined(RT_DEVICE_COMPILATION)
if (enableDebugOutput &&
(executionEnvironment.internalDebugging &
ExecutionEnvironment::WorkQueue)) {
std::fprintf(stderr, "WQ: %zd %s\n", at->ticket.u.index(),
at->ticket.begun ? "Continue" : "Begin");
}
#endif
int stat{at->ticket.Continue(*this)};
#if !defined(RT_DEVICE_COMPILATION)
if (enableDebugOutput &&
(executionEnvironment.internalDebugging &
ExecutionEnvironment::WorkQueue)) {
std::fprintf(stderr, "WQ: ... stat %d\n", stat);
}
#endif
insertAfter_ = nullptr;
if (stat == StatOk) {
if (at->previous) {
at->previous->next = at->next;
} else {
first_ = at->next;
}
if (at->next) {
at->next->previous = at->previous;
} else {
last_ = at->previous;
}
if ((at->next = firstFree_)) {
at->next->previous = at;
}
at->previous = nullptr;
firstFree_ = at;
} else if (stat != StatContinue) {
Stop();
return stat;
}
}
return StatOk;
}
RT_API_ATTRS void WorkQueue::Stop() {
if (last_) {
if ((last_->next = firstFree_)) {
last_->next->previous = last_;
}
firstFree_ = first_;
first_ = last_ = nullptr;
}
}
RT_OFFLOAD_API_GROUP_END
} // namespace Fortran::runtime