summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sc/Library_sc.mk1
-rw-r--r--sc/inc/formulalogger.hxx68
-rw-r--r--sc/source/core/data/formulacell.cxx20
-rw-r--r--sc/source/core/tool/formulalogger.cxx171
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: */