diff options
author | Tor Lillqvist <tml@collabora.com> | 2013-11-07 18:09:58 +0200 |
---|---|---|
committer | Michael Meeks <michael.meeks@collabora.com> | 2013-11-20 18:23:02 +0000 |
commit | 8764c9e91a27f9953be2a5cab54e08cc2eb35278 (patch) | |
tree | 8b89316897df3c08435b597cd71551e1c18173bf /sc | |
parent | 13a8fac05425f9d66c643f25faa49c1f17c62474 (diff) |
Refactoring in preparation for threaded OpenCL kernel compilation
Introduce a new abstract class CompiledFormula, of which the
(existing) class BinaryKernel, that represents one OpenCL kernel, is a
concrete subclass.
Change-Id: I70fd26fa4bd3de026276727bf9fa8ed01bfb62c9
Diffstat (limited to 'sc')
-rw-r--r-- | sc/inc/formulacell.hxx | 7 | ||||
-rw-r--r-- | sc/inc/formulagroup.hxx | 13 | ||||
-rw-r--r-- | sc/inc/types.hxx | 1 | ||||
-rw-r--r-- | sc/source/core/data/formulacell.cxx | 1 | ||||
-rw-r--r-- | sc/source/core/inc/dynamickernel.hxx | 104 | ||||
-rw-r--r-- | sc/source/core/opencl/formulagroupcl.cxx | 140 | ||||
-rw-r--r-- | sc/source/core/tool/formulagroup.cxx | 11 |
7 files changed, 206 insertions, 71 deletions
diff --git a/sc/inc/formulacell.hxx b/sc/inc/formulacell.hxx index c2e578b902ff..b32f25066ce5 100644 --- a/sc/inc/formulacell.hxx +++ b/sc/inc/formulacell.hxx @@ -38,6 +38,12 @@ struct RefUpdateInsertTabContext; struct RefUpdateDeleteTabContext; struct RefUpdateMoveTabContext; +namespace opencl { + +class DynamicKernel; + +} + } class ScProgress; @@ -49,6 +55,7 @@ struct SC_DLLPUBLIC ScFormulaCellGroup : boost::noncopyable mutable size_t mnRefCount; ScTokenArray* mpCode; + sc::opencl::DynamicKernel* mpDynamicKernel; SCROW mnStart; // Start offset of that cell SCROW mnLength; // How many of these do we have ? short mnFormatType; diff --git a/sc/inc/formulagroup.hxx b/sc/inc/formulagroup.hxx index 7c1636457809..faccbfb58fa1 100644 --- a/sc/inc/formulagroup.hxx +++ b/sc/inc/formulagroup.hxx @@ -75,6 +75,13 @@ struct FormulaGroupContext : boost::noncopyable }; /** + * Abstract base class for a "compiled" formula + */ +class SC_DLLPUBLIC CompiledFormula +{ +}; + +/** * Abstract base class for vectorised formula group interpreters, * plus a global instance factory. */ @@ -92,6 +99,9 @@ class SC_DLLPUBLIC FormulaGroupInterpreter static void enableOpenCL(bool bEnable); virtual ScMatrixRef inverseMatrix(const ScMatrix& rMat) = 0; + virtual CompiledFormula* createCompiledFormula(ScDocument& rDoc, + const ScAddress& rTopPos, + ScTokenArray& rCode) = 0; virtual bool interpret(ScDocument& rDoc, const ScAddress& rTopPos, const ScFormulaCellGroupRef& xGroup, ScTokenArray& rCode) = 0; }; @@ -103,6 +113,9 @@ public: virtual ~FormulaGroupInterpreterSoftware() {} virtual ScMatrixRef inverseMatrix(const ScMatrix& rMat); + virtual CompiledFormula* createCompiledFormula(ScDocument& rDoc, + const ScAddress& rTopPos, + ScTokenArray& rCode) SAL_OVERRIDE; virtual bool interpret(ScDocument& rDoc, const ScAddress& rTopPos, const ScFormulaCellGroupRef& xGroup, ScTokenArray& rCode); }; diff --git a/sc/inc/types.hxx b/sc/inc/types.hxx index 045d6b128580..170434124163 100644 --- a/sc/inc/types.hxx +++ b/sc/inc/types.hxx @@ -59,6 +59,7 @@ const sal_uInt16 MatrixEdgeOpen = 32; enum GroupCalcState { GroupCalcEnabled, + GroupCalcOpenCLKernelBinaryCreated, GroupCalcRunning, GroupCalcDisabled }; diff --git a/sc/source/core/data/formulacell.cxx b/sc/source/core/data/formulacell.cxx index ab6dda9799ff..7c48a00a073c 100644 --- a/sc/source/core/data/formulacell.cxx +++ b/sc/source/core/data/formulacell.cxx @@ -385,6 +385,7 @@ void adjustDBRange(ScToken* pToken, ScDocument& rNewDoc, const ScDocument* pOldD ScFormulaCellGroup::ScFormulaCellGroup() : mnRefCount(0), mpCode(NULL), + mpDynamicKernel(NULL), mnStart(0), mnLength(0), mnFormatType(NUMBERFORMAT_NUMBER), diff --git a/sc/source/core/inc/dynamickernel.hxx b/sc/source/core/inc/dynamickernel.hxx new file mode 100644 index 000000000000..e926be556af1 --- /dev/null +++ b/sc/source/core/inc/dynamickernel.hxx @@ -0,0 +1,104 @@ +/* -*- 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/. + */ + +#ifndef INCLUDED_SC_SOURCE_CORE_INC_DYNAMICKERNEL_HXX +#define INCLUDED_SC_SOURCE_CORE_INC_DYNAMICKERNEL_HXX + +#include <config_features.h> + +#include "formulagroup.hxx" + +#if !HAVE_FEATURE_OPENCL + +namespace sc { namespace opencl { + +class DynamikcKernel : public CompiledFormula +{ +} + +} // namespace opencl + +} // namespace sc + +#else + +#include "clew.h" + +#include "document.hxx" +#include "opbase.hxx" + +namespace sc { namespace opencl { + +class DynamicKernelArgument; +class SlidingFunctionBase; + +/// Holds the symbol table for a given dynamic kernel +class SymbolTable { +public: + typedef std::map<const formula::FormulaToken *, + boost::shared_ptr<DynamicKernelArgument> > ArgumentMap; + // This avoids instability caused by using pointer as the key type + typedef std::list< boost::shared_ptr<DynamicKernelArgument> > ArgumentList; + SymbolTable(void):mCurId(0) {} + template <class T> + const DynamicKernelArgument *DeclRefArg(FormulaTreeNodeRef, SlidingFunctionBase* pCodeGen); + /// Used to generate sliding window helpers + void DumpSlidingWindowFunctions(std::stringstream &ss); + /// Memory mapping from host to device and pass buffers to the given kernel as + /// arguments + void Marshal(cl_kernel, int, cl_program); +private: + unsigned int mCurId; + ArgumentMap mSymbols; + ArgumentList mParams; +}; + +class DynamicKernel : public CompiledFormula +{ +public: + DynamicKernel(FormulaTreeNodeRef r):mpRoot(r), + mpProgram(NULL), mpKernel(NULL), mpResClmem(NULL) {} + static DynamicKernel *create(ScDocument& rDoc, + const ScAddress& rTopPos, + ScTokenArray& rCode); + /// Code generation in OpenCL + void CodeGen(); + /// Produce kernel hash + std::string GetMD5(void); + /// Create program, build, and create kerenl + /// TODO cache results based on kernel body hash + /// TODO: abstract OpenCL part out into OpenCL wrapper. + void CreateKernel(void); + /// Prepare buffers, marshal them to GPU, and launch the kernel + /// TODO: abstract OpenCL part out into OpenCL wrapper. + void Launch(size_t nr); + ~DynamicKernel(); + cl_mem GetResultBuffer(void) const { return mpResClmem; } +private: + void TraverseAST(FormulaTreeNodeRef); + FormulaTreeNodeRef mpRoot; + SymbolTable mSyms; + std::string mKernelSignature, mKernelHash; + std::string mFullProgramSrc; + cl_program mpProgram; + cl_kernel mpKernel; + cl_mem mpResClmem; // Results + std::set<std::string> inlineDecl; + std::set<std::string> inlineFun; +}; + +} + +} + +#endif // HAVE_FEATURE_OPENCL + +#endif // INCLUDED_SC_SOURCE_CORE_INC_DYNAMICKERNEL_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/core/opencl/formulagroupcl.cxx b/sc/source/core/opencl/formulagroupcl.cxx index 40df1aeecd95..17536b68c428 100644 --- a/sc/source/core/opencl/formulagroupcl.cxx +++ b/sc/source/core/opencl/formulagroupcl.cxx @@ -16,6 +16,7 @@ #include "formula/vectortoken.hxx" #include "scmatrix.hxx" +#include "dynamickernel.hxx" #include "openclwrapper.hxx" #include "op_financial.hxx" @@ -44,6 +45,7 @@ #include <boost/scoped_ptr.hpp> +#undef NO_FALLBACK_TO_SWINTERP /* undef this for non-TDD runs */ using namespace formula; @@ -2377,33 +2379,16 @@ DynamicKernelSoPArguments::DynamicKernelSoPArguments( }; } } -/// Holds the symbol table for a given dynamic kernel -class SymbolTable { -public: - typedef std::map<const FormulaToken *, - boost::shared_ptr<DynamicKernelArgument> > ArgumentMap; - // This avoids instability caused by using pointer as the key type - typedef std::list< boost::shared_ptr<DynamicKernelArgument> > ArgumentList; - SymbolTable(void):mCurId(0) {} - template <class T> - const DynamicKernelArgument *DeclRefArg(FormulaTreeNodeRef, SlidingFunctionBase* pCodeGen); - /// Used to generate sliding window helpers - void DumpSlidingWindowFunctions(std::stringstream &ss) - { + +/// Used to generate sliding window helpers +void SymbolTable::DumpSlidingWindowFunctions(std::stringstream &ss) +{ for(ArgumentList::iterator it = mParams.begin(), e= mParams.end(); it!=e; ++it) { (*it)->GenSlidingWindowFunction(ss); ss << "\n"; } - } - /// Memory mapping from host to device and pass buffers to the given kernel as - /// arguments - void Marshal(cl_kernel, int, cl_program); -private: - unsigned int mCurId; - ArgumentMap mSymbols; - ArgumentList mParams; -}; +} void SymbolTable::Marshal(cl_kernel k, int nVectorWidth, cl_program pProgram) { @@ -2414,13 +2399,9 @@ void SymbolTable::Marshal(cl_kernel k, int nVectorWidth, cl_program pProgram) } } -/// Code generation -class DynamicKernel { -public: - DynamicKernel(FormulaTreeNodeRef r):mpRoot(r), - mpProgram(NULL), mpKernel(NULL), mpResClmem(NULL) {} /// Code generation in OpenCL - void CodeGen() { +void DynamicKernel::CodeGen() +{ // Travese the tree of expression and declare symbols used const DynamicKernelArgument *DK= mSyms.DeclRefArg< DynamicKernelSoPArguments>(mpRoot, new OpNop); @@ -2456,10 +2437,11 @@ public: #if 1 std::cerr<< "Program to be compiled = \n" << mFullProgramSrc << "\n"; #endif - } - /// Produce kernel hash - std::string GetMD5(void) - { +} + +/// Produce kernel hash +std::string DynamicKernel::GetMD5(void) +{ #ifdef MD5_KERNEL if (mKernelHash.empty()) { std::stringstream md5s; @@ -2478,15 +2460,12 @@ public: #else return ""; #endif - } - /// Create program, build, and create kerenl - /// TODO cache results based on kernel body hash - /// TODO: abstract OpenCL part out into OpenCL wrapper. - void CreateKernel(void); - /// Prepare buffers, marshal them to GPU, and launch the kernel - /// TODO: abstract OpenCL part out into OpenCL wrapper. - void Launch(size_t nr) - { +} + +/// Prepare buffers, marshal them to GPU, and launch the kernel +/// TODO: abstract OpenCL part out into OpenCL wrapper. +void DynamicKernel::Launch(size_t nr) +{ // Obtain cl context KernelEnv kEnv; OpenclDevice::setKernelEnv(&kEnv); @@ -2507,21 +2486,7 @@ public: global_work_size, NULL, 0, NULL, NULL); if (CL_SUCCESS != err) throw OpenCLError(err); - } - ~DynamicKernel(); - cl_mem GetResultBuffer(void) const { return mpResClmem; } -private: - void TraverseAST(FormulaTreeNodeRef); - FormulaTreeNodeRef mpRoot; - SymbolTable mSyms; - std::string mKernelSignature, mKernelHash; - std::string mFullProgramSrc; - cl_program mpProgram; - cl_kernel mpKernel; - cl_mem mpResClmem; // Results - std::set<std::string> inlineDecl; - std::set<std::string> inlineFun; -}; +} DynamicKernel::~DynamicKernel() { @@ -2606,9 +2571,11 @@ public: } virtual ScMatrixRef inverseMatrix( const ScMatrix& rMat ); + virtual CompiledFormula* createCompiledFormula(ScDocument& rDoc, + const ScAddress& rTopPos, + ScTokenArray& rCode); virtual bool interpret( ScDocument& rDoc, const ScAddress& rTopPos, const ScFormulaCellGroupRef& xGroup, ScTokenArray& rCode ); - DynamicKernel *mpKernel; }; ScMatrixRef FormulaGroupInterpreterOpenCL::inverseMatrix( const ScMatrix& ) @@ -2616,11 +2583,10 @@ ScMatrixRef FormulaGroupInterpreterOpenCL::inverseMatrix( const ScMatrix& ) return NULL; } -bool FormulaGroupInterpreterOpenCL::interpret( ScDocument& rDoc, - const ScAddress& rTopPos, const ScFormulaCellGroupRef& xGroup, - ScTokenArray& rCode ) +DynamicKernel* DynamicKernel::create(ScDocument& rDoc, + const ScAddress& rTopPos, + ScTokenArray& rCode) { - // printf("Vector width = %d\n", xGroup->mnLength); // Constructing "AST" FormulaTokenIterator aCode = rCode; std::list<FormulaToken *> list; @@ -2641,7 +2607,7 @@ bool FormulaGroupInterpreterOpenCL::interpret( ScDocument& rDoc, if(m_TempFormula->GetOpCode()!=ocPush) { if(m_hash_map.find(m_TempFormula)==m_hash_map.end()) - return false; + return NULL; m_currNode->Children.push_back(m_hash_map[m_TempFormula]); } else @@ -2661,20 +2627,55 @@ bool FormulaGroupInterpreterOpenCL::interpret( ScDocument& rDoc, FormulaTreeNodeRef Root = FormulaTreeNodeRef(new FormulaTreeNode(NULL)); Root->Children.push_back(m_hash_map[list.back()]); + + DynamicKernel* pDynamicKernel = new DynamicKernel(Root); + + if (!pDynamicKernel) + return NULL; + // Code generation - mpKernel = new DynamicKernel(Root); + try { + pDynamicKernel->CodeGen(); + } + catch (const UnhandledToken &ut) { + std::cerr << "\nDynamic formual compiler: unhandled token: "; + std::cerr << ut.mMessage << "\n"; +#ifdef NO_FALLBACK_TO_SWINTERP + assert(false); +#else + free(pDynamicKernel); + return NULL; +#endif + } + return pDynamicKernel; +} + +CompiledFormula* FormulaGroupInterpreterOpenCL::createCompiledFormula(ScDocument& rDoc, + const ScAddress& rTopPos, + ScTokenArray& rCode) +{ + return sc::opencl::DynamicKernel::create(rDoc, rTopPos, rCode); +} + +bool FormulaGroupInterpreterOpenCL::interpret( ScDocument& rDoc, + const ScAddress& rTopPos, const ScFormulaCellGroupRef& xGroup, + ScTokenArray& rCode ) +{ + // printf("Vector width = %d\n", xGroup->mnLength); + DynamicKernel *pKernel = DynamicKernel::create(rDoc, rTopPos, rCode); + if (!pKernel) + return false; try { - mpKernel->CodeGen(); // Obtain cl context KernelEnv kEnv; OpenclDevice::setKernelEnv(&kEnv); // Compile kernel here!!! - mpKernel->CreateKernel(); + pKernel->CreateKernel(); // Run the kernel. - mpKernel->Launch(xGroup->mnLength); + pKernel->Launch(xGroup->mnLength); // Map results back - cl_mem res = mpKernel->GetResultBuffer(); + cl_mem res = pKernel->GetResultBuffer(); cl_int err; double *resbuf = (double*)clEnqueueMapBuffer(kEnv.mpkCmdQueue, res, @@ -2687,9 +2688,8 @@ bool FormulaGroupInterpreterOpenCL::interpret( ScDocument& rDoc, err = clEnqueueUnmapMemObject(kEnv.mpkCmdQueue, res, resbuf, 0, NULL, NULL); if (err != CL_SUCCESS) throw OpenCLError(err); - delete mpKernel; + delete pKernel; } -#undef NO_FALLBACK_TO_SWINTERP /* undef this for non-TDD runs */ catch (const UnhandledToken &ut) { std::cerr << "\nDynamic formual compiler: unhandled token: "; std::cerr << ut.mMessage << "\n"; @@ -2758,6 +2758,6 @@ SAL_DLLPUBLIC_EXPORT bool SAL_CALL switchOpenClDevice( return sc::opencl::switchOpenclDevice(pDeviceId, bAutoSelect); } -} +} // extern "C" /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/core/tool/formulagroup.cxx b/sc/source/core/tool/formulagroup.cxx index 8eb1fdec7bd3..a31558526d60 100644 --- a/sc/source/core/tool/formulagroup.cxx +++ b/sc/source/core/tool/formulagroup.cxx @@ -16,6 +16,7 @@ #include "compiler.hxx" #include "interpre.hxx" #include "scmatrix.hxx" +#include "dynamickernel.hxx" #include "formula/vectortoken.hxx" #include "rtl/bootstrap.hxx" @@ -284,6 +285,13 @@ ScMatrixRef FormulaGroupInterpreterSoftware::inverseMatrix(const ScMatrix& /*rMa return ScMatrixRef(); } +CompiledFormula* FormulaGroupInterpreterSoftware::createCompiledFormula(ScDocument& /* rDoc */, + const ScAddress& /* rTopPos */, + ScTokenArray& /* rCode */) +{ + return NULL; +} + bool FormulaGroupInterpreterSoftware::interpret(ScDocument& rDoc, const ScAddress& rTopPos, const ScFormulaCellGroupRef& xGroup, ScTokenArray& rCode) @@ -486,6 +494,7 @@ public: FormulaGroupInterpreterOpenCLMissing() : FormulaGroupInterpreter() {} virtual ~FormulaGroupInterpreterOpenCLMissing() {} virtual ScMatrixRef inverseMatrix(const ScMatrix&) { return ScMatrixRef(); } + virtual CompiledFormula* createCompiledFormula(ScDocument&, const ScAddress&, ScTokenArray&) SAL_OVERRIDE { return NULL; } virtual bool interpret(ScDocument&, const ScAddress&, const ScFormulaCellGroupRef&, ScTokenArray&) { return false; } }; @@ -651,6 +660,6 @@ void FormulaGroupInterpreter::enableOpenCL(bool bEnable) ScInterpreter::SetGlobalConfig(aConfig); } -} +} // namespace sc /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |