xref: /core/sc/source/core/tool/formulagroup.cxx (revision 4704acf6)
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
5  * This Source Code Form is subject to the terms of the Mozilla Public
6  * License, v. 2.0. If a copy of the MPL was not distributed with this
7  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8  */
9 
10 #include <config_feature_opencl.h>
11 
12 #include <formulagroup.hxx>
13 #include <formulagroupcl.hxx>
14 #include <document.hxx>
15 #include <formulacell.hxx>
16 #include <tokenarray.hxx>
17 #include <compiler.hxx>
18 #include <interpre.hxx>
19 #include <scmatrix.hxx>
20 #include <globalnames.hxx>
21 #include <comphelper/threadpool.hxx>
22 #include <tools/cpuid.hxx>
23 
24 #include <formula/vectortoken.hxx>
25 #include <officecfg/Office/Common.hxx>
26 #include <officecfg/Office/Calc.hxx>
27 #if HAVE_FEATURE_OPENCL
28 #include <opencl/platforminfo.hxx>
29 #endif
30 #include <rtl/bootstrap.hxx>
31 #include <sal/log.hxx>
32 
33 #include <cstdio>
34 #include <unordered_map>
35 #include <vector>
36 
37 #if HAVE_FEATURE_OPENCL
38 #  include <opencl/openclwrapper.hxx>
39 #endif
40 
41 namespace sc {
42 
43 FormulaGroupEntry::FormulaGroupEntry( ScFormulaCell** pCells, size_t nRow, size_t nLength ) :
44     mpCells(pCells), mnRow(nRow), mnLength(nLength), mbShared(true) {}
45 
46 FormulaGroupEntry::FormulaGroupEntry( ScFormulaCell* pCell, size_t nRow ) :
47     mpCell(pCell), mnRow(nRow), mnLength(0), mbShared(false) {}
48 
49 size_t FormulaGroupContext::ColKey::Hash::operator ()( const FormulaGroupContext::ColKey& rKey ) const
50 {
51     return rKey.mnTab * MAXCOLCOUNT + rKey.mnCol;
52 }
53 
54 FormulaGroupContext::ColKey::ColKey( SCTAB nTab, SCCOL nCol ) : mnTab(nTab), mnCol(nCol) {}
55 
56 bool FormulaGroupContext::ColKey::operator== ( const ColKey& r ) const
57 {
58     return mnTab == r.mnTab && mnCol == r.mnCol;
59 }
60 
61 FormulaGroupContext::ColArray::ColArray( NumArrayType* pNumArray, StrArrayType* pStrArray ) :
62     mpNumArray(pNumArray), mpStrArray(pStrArray), mnSize(0)
63 {
64     if (mpNumArray)
65         mnSize = mpNumArray->size();
66     else if (mpStrArray)
67         mnSize = mpStrArray->size();
68 }
69 
70 FormulaGroupContext::ColArray* FormulaGroupContext::getCachedColArray( SCTAB nTab, SCCOL nCol, size_t nSize )
71 {
72     ColArraysType::iterator itColArray = maColArrays.find(ColKey(nTab, nCol));
73     if (itColArray == maColArrays.end())
74         // Not cached for this column.
75         return nullptr;
76 
77     ColArray& rCached = itColArray->second;
78     if (nSize > rCached.mnSize)
79         // Cached data array is not long enough for the requested range.
80         return nullptr;
81 
82     return &rCached;
83 }
84 
85 FormulaGroupContext::ColArray* FormulaGroupContext::setCachedColArray(
86     SCTAB nTab, SCCOL nCol, NumArrayType* pNumArray, StrArrayType* pStrArray )
87 {
88     ColArraysType::iterator it = maColArrays.find(ColKey(nTab, nCol));
89     if (it == maColArrays.end())
90     {
91         std::pair<ColArraysType::iterator,bool> r =
92             maColArrays.emplace(ColKey(nTab, nCol), ColArray(pNumArray, pStrArray));
93 
94         if (!r.second)
95             // Somehow the insertion failed.
96             return nullptr;
97 
98         return &r.first->second;
99     }
100 
101     // Prior array exists for this column. Overwrite it.
102     ColArray& rArray = it->second;
103     rArray = ColArray(pNumArray, pStrArray);
104     return &rArray;
105 }
106 
107 void FormulaGroupContext::discardCachedColArray( SCTAB nTab, SCCOL nCol )
108 {
109     ColArraysType::iterator itColArray = maColArrays.find(ColKey(nTab, nCol));
110     if (itColArray != maColArrays.end())
111         maColArrays.erase(itColArray);
112 }
113 
114 void FormulaGroupContext::ensureStrArray( ColArray& rColArray, size_t nArrayLen )
115 {
116     if (rColArray.mpStrArray)
117         return;
118 
119     m_StrArrays.push_back(
120         std::make_unique<sc::FormulaGroupContext::StrArrayType>(nArrayLen, nullptr));
121     rColArray.mpStrArray = m_StrArrays.back().get();
122 }
123 
124 void FormulaGroupContext::ensureNumArray( ColArray& rColArray, size_t nArrayLen )
125 {
126     if (rColArray.mpNumArray)
127         return;
128 
129     double fNan;
130     rtl::math::setNan(&fNan);
131 
132     m_NumArrays.push_back(
133         std::make_unique<sc::FormulaGroupContext::NumArrayType>(nArrayLen, fNan));
134     rColArray.mpNumArray = m_NumArrays.back().get();
135 }
136 
137 FormulaGroupContext::FormulaGroupContext()
138 {
139 }
140 
141 FormulaGroupContext::~FormulaGroupContext()
142 {
143 }
144 
145 CompiledFormula::CompiledFormula() {}
146 
147 CompiledFormula::~CompiledFormula() {}
148 
149 FormulaGroupInterpreter *FormulaGroupInterpreter::msInstance = nullptr;
150 
151 void FormulaGroupInterpreter::MergeCalcConfig(const ScDocument& rDoc)
152 {
153     maCalcConfig = ScInterpreter::GetGlobalConfig();
154     maCalcConfig.MergeDocumentSpecific(rDoc.GetCalcConfig());
155 }
156 
157 /// load and/or configure the correct formula group interpreter
158 FormulaGroupInterpreter *FormulaGroupInterpreter::getStatic()
159 {
160     if ( !msInstance )
161     {
162 #if HAVE_FEATURE_OPENCL
163         if (ScCalcConfig::isOpenCLEnabled())
164         {
165             const ScCalcConfig& rConfig = ScInterpreter::GetGlobalConfig();
166             if( !switchOpenCLDevice(rConfig.maOpenCLDevice, rConfig.mbOpenCLAutoSelect))
167             {
168                 if( ScCalcConfig::getForceCalculationType() == ForceCalculationOpenCL )
169                 {
170                     SAL_WARN( "opencl", "OpenCL forced but failed to initialize" );
171                     abort();
172                 }
173             }
174         }
175 #endif
176     }
177 
178     return msInstance;
179 }
180 
181 #if HAVE_FEATURE_OPENCL
182 void FormulaGroupInterpreter::fillOpenCLInfo(std::vector<OpenCLPlatformInfo>& rPlatforms)
183 {
184     const std::vector<OpenCLPlatformInfo>& rPlatformsFromWrapper =
185         openclwrapper::fillOpenCLInfo();
186 
187     rPlatforms.assign(rPlatformsFromWrapper.begin(), rPlatformsFromWrapper.end());
188 }
189 
190 bool FormulaGroupInterpreter::switchOpenCLDevice(const OUString& rDeviceId, bool bAutoSelect, bool bForceEvaluation)
191 {
192     bool bOpenCLEnabled = ScCalcConfig::isOpenCLEnabled();
193     if (!bOpenCLEnabled || (rDeviceId == OPENCL_SOFTWARE_DEVICE_CONFIG_NAME))
194     {
195         delete msInstance;
196         msInstance = nullptr;
197         return false;
198     }
199 
200     OUString aSelectedCLDeviceVersionID;
201     bool bSuccess = openclwrapper::switchOpenCLDevice(&rDeviceId, bAutoSelect, bForceEvaluation, aSelectedCLDeviceVersionID);
202 
203     if (!bSuccess)
204         return false;
205 
206     delete msInstance;
207     msInstance = new sc::opencl::FormulaGroupInterpreterOpenCL();
208 
209     return true;
210 }
211 
212 void FormulaGroupInterpreter::getOpenCLDeviceInfo(sal_Int32& rDeviceId, sal_Int32& rPlatformId)
213 {
214     rDeviceId = -1;
215     rPlatformId = -1;
216     bool bOpenCLEnabled = ScCalcConfig::isOpenCLEnabled();
217     if(!bOpenCLEnabled)
218         return;
219 
220     size_t aDeviceId = static_cast<size_t>(-1);
221     size_t aPlatformId = static_cast<size_t>(-1);
222 
223     openclwrapper::getOpenCLDeviceInfo(aDeviceId, aPlatformId);
224     rDeviceId = aDeviceId;
225     rPlatformId = aPlatformId;
226 }
227 
228 void FormulaGroupInterpreter::enableOpenCL_UnitTestsOnly()
229 {
230     std::shared_ptr<comphelper::ConfigurationChanges> batch(comphelper::ConfigurationChanges::create());
231     officecfg::Office::Common::Misc::UseOpenCL::set(true, batch);
232     batch->commit();
233 
234     ScCalcConfig aConfig = ScInterpreter::GetGlobalConfig();
235 
236     aConfig.mbOpenCLSubsetOnly = false;
237     aConfig.mnOpenCLMinimumFormulaGroupSize = 2;
238 
239     ScInterpreter::SetGlobalConfig(aConfig);
240 }
241 
242 void FormulaGroupInterpreter::disableOpenCL_UnitTestsOnly()
243 {
244     std::shared_ptr<comphelper::ConfigurationChanges> batch(comphelper::ConfigurationChanges::create());
245     officecfg::Office::Common::Misc::UseOpenCL::set(false, batch);
246     batch->commit();
247 }
248 
249 #endif
250 
251 } // namespace sc
252 
253 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
254