
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.
150 lines
3.9 KiB
C++
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
|