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
