diff options
-rw-r--r-- | sc/Library_sc.mk | 1 | ||||
-rw-r--r-- | sc/inc/formulalogger.hxx | 68 | ||||
-rw-r--r-- | sc/source/core/data/formulacell.cxx | 20 | ||||
-rw-r--r-- | sc/source/core/tool/formulalogger.cxx | 171 |
4 files changed, 260 insertions, 0 deletions
diff --git a/sc/Library_sc.mk b/sc/Library_sc.mk index 0aa859e1e19b..f3abc81ac818 100644 --- a/sc/Library_sc.mk +++ b/sc/Library_sc.mk @@ -230,6 +230,7 @@ $(eval $(call gb_Library_add_exception_objects,sc,\ sc/source/core/tool/editutil \ sc/source/core/tool/filtopt \ sc/source/core/tool/formulagroup \ + sc/source/core/tool/formulalogger \ sc/source/core/tool/formulaopt \ sc/source/core/tool/formulaparserpool \ sc/source/core/tool/formularesult \ diff --git a/sc/inc/formulalogger.hxx b/sc/inc/formulalogger.hxx new file mode 100644 index 000000000000..581a2eb63090 --- /dev/null +++ b/sc/inc/formulalogger.hxx @@ -0,0 +1,68 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * 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_INC_FORMULALOGGER_HXX +#define INCLUDED_SC_INC_FORMULALOGGER_HXX + +#include <osl/file.hxx> +#include <memory> +#include <vector> + +class ScFormulaCell; +class ScDocument; + +namespace sc { + +class FormulaLogger +{ + std::unique_ptr<osl::File> mpLogFile; + OUString maGroupPrefix; + std::vector<OUString> maMessages; + + void writeAscii( const char* s ); + void writeAscii( const char* s, size_t n ); + void write( const OUString& ou ); + void write( sal_Int32 n ); + +public: + + /** + * This class is only moveable. + */ + class GroupScope + { + struct Impl; + std::unique_ptr<Impl> mpImpl; + + public: + GroupScope() = delete; + GroupScope( const GroupScope& ) = delete; + GroupScope& operator= ( const GroupScope& ) = delete; + + GroupScope( FormulaLogger& rLogger, const OUString& rPrefix ); + GroupScope( GroupScope&& r ); + ~GroupScope(); + + void addMessage( const OUString& rName ); + + void setCalcComplete(); + }; + + FormulaLogger( const FormulaLogger& ) = delete; + FormulaLogger& operator= ( const FormulaLogger& ) = delete; + + FormulaLogger(); + ~FormulaLogger(); + + GroupScope enterGroup( const ScDocument& rDoc, const ScFormulaCell& rCell ); +}; + +} + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/core/data/formulacell.cxx b/sc/source/core/data/formulacell.cxx index b95417b4a363..a56e128148b2 100644 --- a/sc/source/core/data/formulacell.cxx +++ b/sc/source/core/data/formulacell.cxx @@ -61,6 +61,7 @@ #include <listenerquery.hxx> #include <listenerqueryids.hxx> #include <grouparealistener.hxx> +#include <formulalogger.hxx> #if HAVE_FEATURE_OPENCL #include <opencl/openclwrapper.hxx> @@ -214,6 +215,8 @@ struct DebugCalculationStacker namespace { +sc::FormulaLogger aLogger; + // More or less arbitrary, of course all recursions must fit into available // stack space (which is what on all systems we don't know yet?). Choosing a // lower value may be better than trying a much higher value that also isn't @@ -4030,18 +4033,25 @@ bool ScFormulaCell::InterpretFormulaGroup() if (!mxGroup || !pCode) return false; + auto aScope = aLogger.enterGroup(*pDocument, *this); + if (mxGroup->meCalcState == sc::GroupCalcDisabled) + { + aScope.addMessage("group calc disabled"); return false; + } if (GetWeight() < ScInterpreter::GetGlobalConfig().mnOpenCLMinimumFormulaGroupSize) { mxGroup->meCalcState = sc::GroupCalcDisabled; + aScope.addMessage("group length below minimum threshold"); return false; } if (cMatrixFlag != MM_NONE) { mxGroup->meCalcState = sc::GroupCalcDisabled; + aScope.addMessage("matrix skipped"); return false; } @@ -4055,11 +4065,15 @@ bool ScFormulaCell::InterpretFormulaGroup() case FormulaVectorUnknown: default: // Not good. + aScope.addMessage("group calc disabled due to vector state"); return false; } if (!ScCalcConfig::isOpenCLEnabled() && !ScCalcConfig::isSwInterpreterEnabled()) + { + aScope.addMessage("opencl not enabled"); return false; + } // Guard against endless recursion of Interpret() calls, for this to work // ScFormulaCell::InterpretFormulaGroup() must never be called through @@ -4126,6 +4140,7 @@ bool ScFormulaCell::InterpretFormulaGroup() xGroup->mpCode = nullptr; } + aScope.addMessage("group token conversion failed"); return false; } @@ -4133,6 +4148,7 @@ bool ScFormulaCell::InterpretFormulaGroup() // generate them. xGroup->meCalcState = mxGroup->meCalcState = sc::GroupCalcRunning; sc::FormulaGroupInterpreter *pInterpreter = sc::FormulaGroupInterpreter::getStatic(); + if (pInterpreter == nullptr || !pInterpreter->interpret(*pDocument, xGroup->mpTopCell->aPos, xGroup, aCode)) { @@ -4147,8 +4163,12 @@ bool ScFormulaCell::InterpretFormulaGroup() xGroup->mpCode = nullptr; } + aScope.addMessage("group interpretation unsuccessful"); return false; } + + aScope.setCalcComplete(); + if (nNumParts > 1) { xGroup->mpTopCell = nullptr; diff --git a/sc/source/core/tool/formulalogger.cxx b/sc/source/core/tool/formulalogger.cxx new file mode 100644 index 000000000000..a9ea3ba2fc52 --- /dev/null +++ b/sc/source/core/tool/formulalogger.cxx @@ -0,0 +1,171 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * 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/. + */ + +#include <formulalogger.hxx> +#include <formulacell.hxx> +#include <tokenarray.hxx> +#include <document.hxx> +#include <tokenstringcontext.hxx> + +#include <o3tl/make_unique.hxx> +#include <sfx2/objsh.hxx> +#include <sfx2/docfile.hxx> +#include <tools/urlobj.hxx> + +#include <iostream> + +namespace sc { + +struct FormulaLogger::GroupScope::Impl +{ + FormulaLogger& mrLogger; + + OUString maPrefix; + std::vector<OUString> maMessages; + + bool mbCalcComplete = false; + + Impl( FormulaLogger& rLogger, const OUString& rPrefix ) : + mrLogger(rLogger), maPrefix(rPrefix) {} + + ~Impl() + { + for (const OUString& rMsg : maMessages) + { + mrLogger.write(maPrefix); + mrLogger.writeAscii(" * "); + mrLogger.write(rMsg); + mrLogger.writeAscii("\n"); + } + + mrLogger.write(maPrefix); + mrLogger.writeAscii(mbCalcComplete ? " * calculation complete\n" : " * exited without calculation\n"); + + mrLogger.mpLogFile->sync(); + } +}; + +FormulaLogger::GroupScope::GroupScope( FormulaLogger& rLogger, const OUString& rPrefix ) : + mpImpl(o3tl::make_unique<Impl>(rLogger, rPrefix)) {} + +FormulaLogger::GroupScope::GroupScope( GroupScope&& r ) : mpImpl(std::move(r.mpImpl)) {} + +FormulaLogger::GroupScope::~GroupScope() {} + +void FormulaLogger::GroupScope::addMessage( const OUString& rMsg ) +{ + mpImpl->maMessages.push_back(rMsg); +} + +void FormulaLogger::GroupScope::setCalcComplete() +{ + mpImpl->mbCalcComplete; +} + +FormulaLogger::FormulaLogger() : mpLogFile(o3tl::make_unique<osl::File>("file:///home/kohei/tmp/formula.log")) +{ + osl::FileBase::RC eRC = mpLogFile->open(osl_File_OpenFlag_Write | osl_File_OpenFlag_Create); + + if (eRC == osl::FileBase::E_EXIST) + { + eRC = mpLogFile->open(osl_File_OpenFlag_Write); + + if (eRC != osl::FileBase::E_None) + { + // Failed to open an existing log file. + mpLogFile.reset(); + return; + } + + if (mpLogFile->setPos(osl_Pos_End, 0) != osl::FileBase::E_None) + { + // Failed to set the position to the end of the file. + mpLogFile.reset(); + return; + } + } + else if (eRC != osl::FileBase::E_None) + { + // Failed to create a new file. + mpLogFile.reset(); + return; + } + + sal_uInt64 nBytes; + mpLogFile->write("---\n", 4, nBytes); + mpLogFile->sync(); +} + +FormulaLogger::~FormulaLogger() +{ + if (mpLogFile) + mpLogFile->close(); +} + +void FormulaLogger::writeAscii( const char* s ) +{ + if (!mpLogFile) + return; + + sal_uInt64 nBytes; + mpLogFile->write(s, strlen(s), nBytes); +} + +void FormulaLogger::writeAscii( const char* s, size_t n ) +{ + if (!mpLogFile) + return; + + sal_uInt64 nBytes; + mpLogFile->write(s, n, nBytes); +} + +void FormulaLogger::write( const OUString& ou ) +{ + OString s = rtl::OUStringToOString(ou, RTL_TEXTENCODING_UTF8).getStr(); + writeAscii(s.getStr(), s.getLength()); +} + +void FormulaLogger::write( sal_Int32 n ) +{ + OString s = OString::number(n); + writeAscii(s.getStr(), s.getLength()); +} + +FormulaLogger::GroupScope FormulaLogger::enterGroup( + const ScDocument& rDoc, const ScFormulaCell& rCell ) +{ + maGroupPrefix = "formula-group: "; + + // Get the file name if available. + const SfxObjectShell* pShell = rDoc.GetDocumentShell(); + const SfxMedium* pMedium = pShell->GetMedium(); + OUString aName = pMedium->GetURLObject().GetLastName(); + if (aName.isEmpty()) + aName = "-"; // unsaved document. + + maGroupPrefix += aName; + maGroupPrefix += ": "; + maGroupPrefix += rCell.aPos.Format(ScRefFlags::VALID | ScRefFlags::TAB_3D, &rDoc, rDoc.GetAddressConvention()); + maGroupPrefix += ": "; + write(maGroupPrefix); + + writeAscii("(formula='"); + + sc::TokenStringContext aCxt(&rDoc, rDoc.GetGrammar()); + write(rCell.GetCode()->CreateString(aCxt, rCell.aPos)); + + writeAscii("', size="); + write(rCell.GetSharedLength()); + writeAscii(")\n"); + + return GroupScope(*this, maGroupPrefix); +} + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |