Profiling a basic internal real input read benchmark shows some hot spots in the code used to prepare input for decimal-to-binary conversion, which is of course where the time should be spent. The library that implements decimal to/from binary conversions has been optimized, but not the code in the Fortran runtime that calls it, and there are some obvious light changes worth making here. Move some member functions from *.cpp files into the class definitions of Descriptor and IoStatementState to enable inlining and specialization. Make GetNextInputBytes() the new basic input API within the runtime, replacing GetCurrentChar() -- which is rewritten in terms of GetNextInputBytes -- so that input routines can have the ability to acquire more than one input character at a time and amortize overhead. These changes speed up the time to read 1M random reals using internal I/O from a character array from 1.29s to 0.54s on my machine, which on par with Intel Fortran and much faster than GNU Fortran. Differential Revision: https://reviews.llvm.org/D113697
55 lines
1.9 KiB
C++
55 lines
1.9 KiB
C++
//===-- runtime/internal-unit.h ---------------------------------*- 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
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Fortran internal I/O "units"
|
|
|
|
#ifndef FORTRAN_RUNTIME_IO_INTERNAL_UNIT_H_
|
|
#define FORTRAN_RUNTIME_IO_INTERNAL_UNIT_H_
|
|
|
|
#include "connection.h"
|
|
#include "flang/Runtime/descriptor.h"
|
|
#include <cinttypes>
|
|
#include <type_traits>
|
|
|
|
namespace Fortran::runtime::io {
|
|
|
|
class IoErrorHandler;
|
|
|
|
// Points to (but does not own) a CHARACTER scalar or array for internal I/O.
|
|
// Does not buffer.
|
|
template <Direction DIR> class InternalDescriptorUnit : public ConnectionState {
|
|
public:
|
|
using Scalar =
|
|
std::conditional_t<DIR == Direction::Input, const char *, char *>;
|
|
InternalDescriptorUnit(Scalar, std::size_t);
|
|
InternalDescriptorUnit(const Descriptor &, const Terminator &);
|
|
void EndIoStatement();
|
|
|
|
bool Emit(const char *, std::size_t, IoErrorHandler &);
|
|
std::size_t GetNextInputBytes(const char *&, IoErrorHandler &);
|
|
std::optional<char32_t> GetCurrentChar(IoErrorHandler &);
|
|
bool AdvanceRecord(IoErrorHandler &);
|
|
void BackspaceRecord(IoErrorHandler &);
|
|
|
|
private:
|
|
Descriptor &descriptor() { return staticDescriptor_.descriptor(); }
|
|
const Descriptor &descriptor() const {
|
|
return staticDescriptor_.descriptor();
|
|
}
|
|
Scalar CurrentRecord() const {
|
|
return descriptor().template ZeroBasedIndexedElement<char>(
|
|
currentRecordNumber - 1);
|
|
}
|
|
StaticDescriptor<maxRank, true /*addendum*/> staticDescriptor_;
|
|
};
|
|
|
|
extern template class InternalDescriptorUnit<Direction::Output>;
|
|
extern template class InternalDescriptorUnit<Direction::Input>;
|
|
} // namespace Fortran::runtime::io
|
|
#endif // FORTRAN_RUNTIME_IO_INTERNAL_UNIT_H_
|