/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
// FIXME: The idea that somebody would bother to (now and then? once a year? once a month?) manually // edit a source file and change the value of some #defined constant and run some ill-defined // "correctness test" is of course ludicrous. Either things are checked in normal unit tests, in // every 'make check', or not at all. The below comments are ridiculous.
constexpr auto REDUCE_THRESHOLD = 201; // set to 4 for correctness testing. priority 1
constexpr auto UNROLLING_FACTOR = 16; // set to 4 for correctness testing (if no reduce)
class FormulaTreeNode;
/// Exceptions
/// Failed in parsing class UnhandledToken
{ public:
UnhandledToken( constchar* m, std::string fn, int ln );
std::string mMessage;
std::string mFile; int mLineNumber;
};
/// Failed in marshaling class OpenCLError
{ public:
OpenCLError( std::string function, cl_int error, std::string file, int line );
std::string mFunction;
cl_int mError;
std::string mFile; int mLineNumber;
};
/// Inconsistent state class Unhandled
{ public:
Unhandled( std::string fn, int ln );
std::string mFile; int mLineNumber;
};
class InvalidParameterCount
{ public:
InvalidParameterCount( int parameterCount, std::string file, int ln );
int mParameterCount;
std::string mFile; intconst mLineNumber;
};
// Helper macros to be used in code emitting OpenCL code for Calc functions. // Require the vSubArguments parameter. #define CHECK_PARAMETER_COUNT(min, max) \ do { \ constint count = vSubArguments.size(); \ if( count < ( min ) || count > ( max )) \ throw InvalidParameterCount( count, __FILE__, __LINE__ ); \
} while( false ) #define CHECK_PARAMETER_COUNT_MIN(min) \ do { \ constint count = vSubArguments.size(); \ if( count < ( min )) \ throw InvalidParameterCount( count, __FILE__, __LINE__ ); \
} while( false ) #define CHECK_PARAMETER_DOUBLEVECTORREF(arg) \ do { \
formula::FormulaToken *token = vSubArguments[arg]->GetFormulaToken(); \ if (token == nullptr || token->GetType() != formula::svDoubleVectorRef) \ throw Unhandled(__FILE__, __LINE__); \
} while( false )
/// (Partially) abstract base class for an operand class DynamicKernelArgument
{ public: /// delete copy constructor
DynamicKernelArgument( const DynamicKernelArgument& ) = delete;
/// Holds an input (read-only) argument reference to a SingleVectorRef. /// or a DoubleVectorRef for non-sliding-window argument of complex functions /// like SumOfProduct /// In most of the cases the argument is introduced /// by a Push operation in the given RPN. class VectorRef : public DynamicKernelArgument
{ public:
VectorRef( const ScCalcConfig& config, const std::string& s, const FormulaTreeNodeRef& ft, int index = 0 ); virtual ~VectorRef() override;
/// Generate declaration virtualvoid GenDecl( outputstream& ss ) const override; /// When declared as input to a sliding window function virtualvoid GenSlidingWindowDecl( outputstream& ss ) const override;
/// When referenced in a sliding window function virtual std::string GenSlidingWindowDeclRef( bool = false ) const override;
/// Create buffer and pass the buffer to a given kernel virtual size_t Marshal( cl_kernel, int, int, cl_program ) override;
protected: // Used by marshaling
cl_mem mpClmem; // index in multiple double vector refs that have multiple ranges constint mnIndex; // Makes Marshall convert strings to 0 values. bool forceStringsToZero; // Used for storing when the data needs to be modified before sending to OpenCL.
std::vector< double > dataBuffer;
};
// Sets VectorRef::forceStringsToZero. class VectorRefStringsToZero : public VectorRef
{ public:
VectorRefStringsToZero( const ScCalcConfig& config, const std::string& s, constFormulaTreeNodeRef& ft, int index = 0 );
};
/// A vector of strings class DynamicKernelStringArgument : public VectorRef
{ public:
DynamicKernelStringArgument( const ScCalcConfig& config, const std::string& s, const FormulaTreeNodeRef& ft, int index = 0 ) :
VectorRef(config, s, ft, index) { }
/// Arguments that are actually compile-time constants class DynamicKernelConstantArgument : public DynamicKernelArgument
{ public:
DynamicKernelConstantArgument( const ScCalcConfig& config, const std::string& s, const FormulaTreeNodeRef& ft ) :
DynamicKernelArgument(config, s, ft) { } /// Generate declaration virtualvoid GenDecl( outputstream& ss ) const override
{
ss << "double " << mSymName;
} virtualvoid GenDeclRef( outputstream& ss ) const override
{
ss << mSymName;
} virtualvoid GenSlidingWindowDecl( outputstream& ss ) const override
{
GenDecl(ss);
} virtual std::string GenSlidingWindowDeclRef( bool = false ) const override
{ if (GetFormulaToken()->GetType() != formula::svDouble) throw Unhandled(__FILE__, __LINE__); return mSymName;
} virtual size_t GetWindowSize() const override
{ return 1;
} virtualdouble GetDouble() const
{
formula::FormulaToken* Tok = GetFormulaToken(); if (Tok->GetType() != formula::svDouble) throw Unhandled(__FILE__, __LINE__); return Tok->GetDouble();
} /// Create buffer and pass the buffer to a given kernel virtual size_t Marshal( cl_kernel k, int argno, int, cl_program ) override
{
OpenCLZone zone; double tmp = GetDouble(); // Pass the scalar result back to the rest of the formula kernel
SAL_INFO("sc.opencl", "Kernel " << k << " arg " << argno << ": double: " << preciseFloat( tmp ));
cl_int err = clSetKernelArg(k, argno, sizeof(double), static_cast<void*>(&tmp)); if (CL_SUCCESS != err) throw OpenCLError("clSetKernelArg", err, __FILE__, __LINE__); return 1;
}
};
// Constant 0 argument when a string is forced to zero. class DynamicKernelStringToZeroArgument : public DynamicKernelConstantArgument
{ public:
DynamicKernelStringToZeroArgument( const ScCalcConfig& config, const std::string& s, const FormulaTreeNodeRef& ft ) :
DynamicKernelConstantArgument(config, s, ft) { } virtual std::string GenSlidingWindowDeclRef( bool = false ) const override
{ return mSymName;
} virtualdouble GetDouble() const override { return 0; }
};
/// Abstract class for code generation class OpBase
{ public: // FIXME: What exactly is this? It seems to be a starting value for some calculations // (1 for OpMul, MAXFLOAT for OpMin), but it's often used pointlessly and sometimes // even incorrectly (default value for when the cell is empty). virtual std::string GetBottom() { return"";}; virtual std::string Gen2( const std::string&/*lhs*/, const std::string&/*rhs*/ ) const { return "";} static std::string Gen( std::vector<std::string>& /*argVector*/ ) { return "";}; virtual std::string BinFuncName() const { return"";}; virtualvoid BinInlineFun( std::set<std::string>&,
std::set<std::string>& ) { } virtualbool takeString() const = 0; virtualbool takeNumeric() const = 0; // Whether DoubleRef containing more than one column is handled properly. virtualbool canHandleMultiVector() const { returnfalse; } //Continue process 'Zero' or Not(like OpMul, not continue process when meet // 'Zero' virtualbool ZeroReturnZero() { returnfalse;} // For use with COUNTA() etc, input strings will be converted to 0 in data. virtualbool forceStringsToZero() const { returnfalse; } virtual ~OpBase() { }
};
class SlidingFunctionBase : public OpBase
{ public: typedef std::vector<DynamicKernelArgumentRef> SubArguments; virtualvoid GenSlidingWindowFunction( outputstream&, const std::string&, SubArguments& ) = 0; protected: // This enum controls how the generated code will handle empty cells in ranges. enum EmptyArgType
{
EmptyIsZero, // empty cells become 0.0
EmptyIsNan, // empty cells become NAN, use isnan() to check in code
SkipEmpty // empty cells will be skipped
}; // This enum controls whether the generated code will also include variable // <name>_is_string that will be set depending on the value type. enum GenerateArgTypeType
{
DoNotGenerateArgType,
GenerateArgType
}; void GenerateFunctionDeclaration( const std::string& sSymName,
SubArguments& vSubArguments, outputstream& ss ); // Generate code for "double <name> = <value>;" from vSubArguments, svDoubleVectorRef is not supported. void GenerateArg( constchar* name, int arg, SubArguments& vSubArguments, outputstream& ss,
EmptyArgType empty = EmptyIsZero, GenerateArgTypeType generateType = DoNotGenerateArgType ); // overload, variable will be named "arg<arg>" void GenerateArg( int arg, SubArguments& vSubArguments, outputstream& ss,
EmptyArgType empty = EmptyIsZero, GenerateArgTypeType generateType = DoNotGenerateArgType ); // generate code for "double <name> = <value>;" from vSubArguments, if it exists, // otherwise set to <def> void GenerateArgWithDefault( constchar* name, int arg, double def, SubArguments& vSubArguments,
outputstream& ss, EmptyArgType empty = EmptyIsZero ); // Generate code that will handle all arguments firstArg-lastArg (zero-based, inclusive), // including range arguments (svDoubleVectorRef) and each value will be processed by 'code', // value will be named "arg". staticvoid GenerateRangeArgs( int firstArg, int lastArg, SubArguments& vSubArguments,
outputstream& ss, EmptyArgType empty, constchar* code ); // overload, handle all arguments staticvoid GenerateRangeArgs( SubArguments& vSubArguments, outputstream& ss,
EmptyArgType empty, constchar* code ); // overload, handle the given argument staticvoid GenerateRangeArg( int arg, SubArguments& vSubArguments, outputstream& ss,
EmptyArgType empty, constchar* code ); // Overload. // Both arguments must be svDoubleRef of the same size. // If 'firstElementDiff' is set, the loop start will be offset by '+ firstElementDiff'. void GenerateRangeArg( int arg1, int arg2, SubArguments& vSubArguments,
outputstream& ss, EmptyArgType empty, constchar* code, constchar* firstElementDiff = nullptr ); // Generate code that will handle the given two arguments in one loop where n-th element of arg1 and arg2 // will be handled at the same time, named 'arg1' and 'arg2'. // Both arguments must be svDoubleRef of the same size. // If 'firstElementDiff' is set, the loop start will be offset by '+ firstElementDiff'. staticvoid GenerateRangeArgPair( int arg1, int arg2, SubArguments& vSubArguments,
outputstream& ss, EmptyArgType empty, constchar* code, constchar* firstElementDiff = nullptr ); // Generate code for "double <name> = range[<element>]" from vSubArguments. // The argument must be svDoubleRef. staticvoid GenerateRangeArgElement( constchar* name, int arg, constchar* element,
SubArguments& vSubArguments, outputstream& ss, EmptyArgType empty ); staticvoid GenerateDoubleVectorLoopHeader( outputstream& ss, const formula::DoubleVectorRefToken* pDVR, constchar* firstElementDiff );
};
class CheckVariables : public Normal
{ public: staticvoid GenTmpVariables( outputstream& ss, const SubArguments& vSubArguments ); staticvoid CheckSubArgumentIsNan( outputstream& ss,
SubArguments& vSubArguments, int argumentNum ); staticvoid CheckAllSubArgumentIsNan( outputstream& ss,
SubArguments& vSubArguments ); // only check isnan staticvoid CheckSubArgumentIsNan2( outputstream& ss,
SubArguments& vSubArguments, int argumentNum, const std::string& p ); staticvoid UnrollDoubleVector( outputstream& ss, const outputstream& unrollstr, const formula::DoubleVectorRefToken* pCurDVR, int nCurWindowSize );
};
/// Handling a Double Vector that is used as a sliding window input /// to either a sliding window average or sum-of-products /// Generate a sequential loop for reductions template<class Base> class DynamicKernelSlidingArgument : public Base
{ public:
DynamicKernelSlidingArgument(const ScCalcConfig& config, const std::string& s, const FormulaTreeNodeRef& ft,
std::shared_ptr<SlidingFunctionBase> CodeGen, int index); // Should only be called by SumIfs. Yikes! virtualbool NeedParallelReduction() const; virtualvoid GenSlidingWindowFunction( outputstream& ) { }
std::string GenSlidingWindowDeclRef( bool nested = false ) const; /// Controls how the elements in the DoubleVectorRef are traversed
size_t GenReductionLoopHeader( outputstream& ss, bool& needBody );
/// Handling a Double Vector that is used as a sliding window input /// Performs parallel reduction based on given operator template<class Base> class ParallelReductionVectorRef : public Base
{ public:
ParallelReductionVectorRef(const ScCalcConfig& config, const std::string& s, const FormulaTreeNodeRef& ft,
std::shared_ptr<SlidingFunctionBase> CodeGen, int index);
~ParallelReductionVectorRef();
/// Emit the definition for the auxiliary reduction kernel virtualvoid GenSlidingWindowFunction( outputstream& ss ); virtual std::string GenSlidingWindowDeclRef( bool ) const; /// Controls how the elements in the DoubleVectorRef are traversed
size_t GenReductionLoopHeader( outputstream& ss, int nResultSize, bool& needBody ); virtual size_t Marshal( cl_kernel k, int argno, int w, cl_program mpProgram );
size_t GetArrayLength() const { return mpDVR->GetArrayLength(); }
size_t GetWindowSize() const { return mpDVR->GetRefRowSize(); } bool GetStartFixed() const { return bIsStartFixed; } bool GetEndFixed() const { return bIsEndFixed; }
protected: bool bIsStartFixed, bIsEndFixed; const formula::DoubleVectorRefToken* mpDVR; // from parent nodes
std::shared_ptr<SlidingFunctionBase> mpCodeGen; // controls whether to invoke the reduction kernel during marshaling or not
cl_mem mpClmem2;
};
class Reduction : public SlidingFunctionBase
{ intconst mnResultSize; public: explicit Reduction(int nResultSize) : mnResultSize(nResultSize) {}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.