From 244f60531260cf6e88e764b5c271d5c9183b5d1a Mon Sep 17 00:00:00 2001 From: Tor Lillqvist Date: Thu, 10 Aug 2017 17:13:45 +0300 Subject: [PATCH] Add a unit test to be used to test parallelised calculations in Calc Currently only tests SUMIFS. Yes, it would be nice if some of the already existing unit tests would work for this need, too. But there are various reasons wny not. Also, don't want to interfere in ongoing work by others. Change-Id: Ie9008a4a1a8c26eff4f2ab0bc91294b2239f0ae1 --- sc/CppunitTest_sc_parallelism.mk | 108 +++++++++++++++ sc/Module_sc.mk | 1 + sc/inc/formulagroup.hxx | 1 + sc/qa/unit/parallelism.cxx | 181 ++++++++++++++++++++++++++ sc/source/core/tool/formulagroup.cxx | 7 + sc/source/core/tool/formulalogger.cxx | 4 +- 6 files changed, 301 insertions(+), 1 deletion(-) create mode 100644 sc/CppunitTest_sc_parallelism.mk create mode 100644 sc/qa/unit/parallelism.cxx diff --git a/sc/CppunitTest_sc_parallelism.mk b/sc/CppunitTest_sc_parallelism.mk new file mode 100644 index 000000000000..a411caee2ae2 --- /dev/null +++ b/sc/CppunitTest_sc_parallelism.mk @@ -0,0 +1,108 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# 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/. +# + +$(eval $(call gb_CppunitTest_CppunitTest,sc_parallelism)) + +$(eval $(call gb_CppunitTest_add_exception_objects,sc_parallelism, \ + sc/qa/unit/parallelism \ +)) + +$(eval $(call gb_CppunitTest_use_externals,sc_parallelism, \ + boost_headers \ + $(call gb_Helper_optional,OPENCL,clew) \ + mdds_headers \ +)) + +$(eval $(call gb_CppunitTest_use_libraries,sc_parallelism, \ + basegfx \ + comphelper \ + cppu \ + cppuhelper \ + drawinglayer \ + editeng \ + for \ + forui \ + i18nlangtag \ + msfilter \ + oox \ + sal \ + salhelper \ + sax \ + sc \ + scqahelper \ + sfx \ + sot \ + svl \ + svt \ + svx \ + svxcore \ + test \ + tk \ + tl \ + ucbhelper \ + unotest \ + utl \ + vcl \ + xo \ +)) + +$(eval $(call gb_CppunitTest_set_include,sc_parallelism,\ + -I$(SRCDIR)/sc/source/ui/inc \ + -I$(SRCDIR)/sc/source/core/inc \ + -I$(SRCDIR)/sc/inc \ + $$(INCLUDE) \ +)) + +$(eval $(call gb_CppunitTest_use_sdk_api,sc_parallelism)) + +$(eval $(call gb_CppunitTest_use_ure,sc_parallelism)) +$(eval $(call gb_CppunitTest_use_vcl,sc_parallelism)) + +$(eval $(call gb_CppunitTest_use_components,sc_parallelism,\ + basic/util/sb \ + chart2/source/chartcore \ + chart2/source/controller/chartcontroller \ + comphelper/util/comphelp \ + configmgr/source/configmgr \ + dbaccess/util/dba \ + embeddedobj/util/embobj \ + eventattacher/source/evtatt \ + filter/source/config/cache/filterconfig1 \ + forms/util/frm \ + framework/util/fwk \ + i18npool/util/i18npool \ + linguistic/source/lng \ + oox/util/oox \ + package/source/xstor/xstor \ + package/util/package2 \ + sax/source/expatwrap/expwrap \ + scaddins/source/analysis/analysis \ + scaddins/source/datefunc/date \ + sc/util/sc \ + sc/util/scfilt \ + sfx2/util/sfx \ + sot/util/sot \ + svl/util/svl \ + svtools/util/svt \ + svx/util/svx \ + svx/util/svxcore \ + toolkit/util/tk \ + ucb/source/core/ucb1 \ + ucb/source/ucp/file/ucpfile1 \ + ucb/source/ucp/tdoc/ucptdoc1 \ + uui/util/uui \ + unotools/util/utl \ + unoxml/source/rdf/unordf \ + unoxml/source/service/unoxml \ + xmloff/util/xo \ +)) + +$(eval $(call gb_CppunitTest_use_configuration,sc_parallelism)) + +# vim: set noet sw=4 ts=4: diff --git a/sc/Module_sc.mk b/sc/Module_sc.mk index 9080ec3a4433..6a6a538d189c 100644 --- a/sc/Module_sc.mk +++ b/sc/Module_sc.mk @@ -96,6 +96,7 @@ $(eval $(call gb_Module_add_subsequentcheck_targets,sc,\ JunitTest_sc_unoapi_6 \ JunitTest_sc_unoapi_7 \ CppunitTest_sc_opencl_test \ + CppunitTest_sc_parallelism \ CppunitTest_sc_anchor_test \ CppunitTest_sc_annotationshapeobj \ CppunitTest_sc_outlineobj \ diff --git a/sc/inc/formulagroup.hxx b/sc/inc/formulagroup.hxx index f51a592e0d60..a02157439448 100644 --- a/sc/inc/formulagroup.hxx +++ b/sc/inc/formulagroup.hxx @@ -138,6 +138,7 @@ public: static bool switchOpenCLDevice(const OUString& rDeviceId, bool bAutoSelect, bool bForceEvaluation = false); // This is intended to be called from opencl-test.cxx only static void enableOpenCL_UnitTestsOnly(); + static void disableOpenCL_UnitTestsOnly(); static void getOpenCLDeviceInfo(sal_Int32& rDeviceId, sal_Int32& rPlatformId); #endif virtual ScMatrixRef inverseMatrix(const ScMatrix& rMat) = 0; diff --git a/sc/qa/unit/parallelism.cxx b/sc/qa/unit/parallelism.cxx new file mode 100644 index 000000000000..4614827d04c8 --- /dev/null +++ b/sc/qa/unit/parallelism.cxx @@ -0,0 +1,181 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */ + +#include +#include +#include +#include + +#include "scdll.hxx" +#include +#include +#include +#include +#include + +#include "helper/qahelper.hxx" + +#include "calcconfig.hxx" +#include "interpre.hxx" + +#include "docsh.hxx" +#include "postit.hxx" +#include "patattr.hxx" +#include "scitems.hxx" +#include "document.hxx" +#include "cellform.hxx" +#include "drwlayer.hxx" +#include "userdat.hxx" +#include "formulacell.hxx" +#include "formulagroup.hxx" + +#include + +using namespace css; +using namespace css::uno; + +class ScParallelismTest : public ScBootstrapFixture +{ +public: + ScParallelismTest(); + + virtual void setUp() override; + virtual void tearDown() override; + + void getNewDocShell(ScDocShellRef& rDocShellRef); + + void testSUMIFS(); + + CPPUNIT_TEST_SUITE(ScParallelismTest); + CPPUNIT_TEST(testSUMIFS); + CPPUNIT_TEST_SUITE_END(); + +private: + ScDocument *m_pDoc; + + ScDocShellRef m_xDocShell; +}; + +ScParallelismTest::ScParallelismTest() + : ScBootstrapFixture( "/sc/qa/unit/data" ) +{ +} + +void ScParallelismTest::setUp() +{ + test::BootstrapFixture::setUp(); + + ScDLL::Init(); + + getNewDocShell(m_xDocShell); + m_pDoc = &m_xDocShell->GetDocument(); + + sc::FormulaGroupInterpreter::disableOpenCL_UnitTestsOnly(); +} + +void ScParallelismTest::tearDown() +{ + if(m_xDocShell.is()) + { + m_xDocShell->DoClose(); + m_xDocShell.clear(); + } + + test::BootstrapFixture::tearDown(); +} + +void ScParallelismTest::getNewDocShell( ScDocShellRef& rDocShellRef ) +{ + rDocShellRef = new ScDocShell( + SfxModelFlags::EMBEDDED_OBJECT | + SfxModelFlags::DISABLE_EMBEDDED_SCRIPTS | + SfxModelFlags::DISABLE_DOCUMENT_RECOVERY); +} + +void ScParallelismTest::testSUMIFS() +{ + m_pDoc->InsertTab(0, "1"); + + m_pDoc->SetValue(0, 0, 0, 1001); + + /*E1*/ m_pDoc->SetFormula(ScAddress(5, 0, 0), + "=$F$2+$F$3", + formula::FormulaGrammar::GRAM_ENGLISH); + /*F1*/ m_pDoc->SetFormula(ScAddress(6, 0, 0), + "=SUM($F$2:$F$3)", + formula::FormulaGrammar::GRAM_ENGLISH); + + for (auto i = 1; i < 1000; i++) + { + /*A*/ m_pDoc->SetValue(0, i, 0, i/10 + 1000); + /*B*/ m_pDoc->SetValue(1, i, 0, i%10); + /*C*/ m_pDoc->SetValue(2, i, 0, i%5); + + /*F*/ m_pDoc->SetValue(5, i, 0, i%17 + i%13); + + /*L*/ m_pDoc->SetValue(11, i, 0, i%10); + /*M*/ m_pDoc->SetValue(12, i, 0, i%5); + } + + for (auto i = 1; i < 1000; i++) + { + // For instance P389 will contain the formula: + // =SUMIFS($F$2:$F$1000; $A$2:$A$1000; A$1; $B$2:$B$1000; $L389; $C$2:$C$1000; $M389) + + // In other words, it will sum those values in F2:1000 where the A value matches A1 (1001), + // the B value matches L389 and the C value matches M389. (There should be just one such + // value, so the formula is actually simply used to pick out that single value from the F + // column where A,B,C match. Silly, but that is how SUMIFS is used in some corners of the + // real world, apparently.) + + /*P*/ m_pDoc->SetFormula(ScAddress(15, i, 0), + "=SUMIFS($F$2:$F$1000; " + "$A$2:$A$1000; A$1; " + "$B$2:$B$1000; $L" + OUString::number(i+1) + "; " + "$C$2:$C$1000; $M" + OUString::number(i+1) + + ")", + formula::FormulaGrammar::GRAM_NATIVE_UI); + } + + m_xDocShell->DoHardRecalc(); + +#if 1 + OUString sFormula; + + std::cerr << "A1=" << m_pDoc->GetValue(0, 0, 0) << std::endl; + + m_pDoc->GetFormula(5, 0, 0, sFormula); + std::cerr << "E1=" << "\"" << sFormula << "\"=" << m_pDoc->GetValue(5, 0, 0) << std::endl; + + m_pDoc->GetFormula(6, 0, 0, sFormula); + std::cerr << "F1=" << "\"" << sFormula << "\"=" << m_pDoc->GetValue(6, 0, 0) << std::endl; + + std::cerr << " A,B,C F L,M" << std::endl; + for (auto i = 1; i < 30; i++) + { + std::cerr << + i+1 << ": " << + m_pDoc->GetValue(0, i, 0) << "," << + m_pDoc->GetValue(1, i, 0) << "," << + m_pDoc->GetValue(2, i, 0) << " " << + m_pDoc->GetValue(5, i, 0) << " " << + m_pDoc->GetValue(11, i, 0) << "," << + m_pDoc->GetValue(12, i, 0) << " \""; + m_pDoc->GetFormula(15, i, 0, sFormula); + std::cerr << sFormula << "\": \"" << + m_pDoc->GetString(15, i, 0) << "\": " << + m_pDoc->GetValue(15, i, 0) << std::endl; + } +#endif + + for (auto i = 1; i < 1000; i++) + { + OString sMessage = "At row " + OString::number(i+1); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE(sMessage.getStr(), m_pDoc->GetValue(5, 10+i%10, 0), m_pDoc->GetValue(15, i, 0), 1e-10); + } +} + +CPPUNIT_TEST_SUITE_REGISTRATION(ScParallelismTest); + +CPPUNIT_PLUGIN_IMPLEMENT(); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/core/tool/formulagroup.cxx b/sc/source/core/tool/formulagroup.cxx index 590215a2ad42..985d5cdfed43 100644 --- a/sc/source/core/tool/formulagroup.cxx +++ b/sc/source/core/tool/formulagroup.cxx @@ -369,6 +369,13 @@ void FormulaGroupInterpreter::enableOpenCL_UnitTestsOnly() ScInterpreter::SetGlobalConfig(aConfig); } +void FormulaGroupInterpreter::disableOpenCL_UnitTestsOnly() +{ + std::shared_ptr batch(comphelper::ConfigurationChanges::create()); + officecfg::Office::Common::Misc::UseOpenCL::set(false, batch); + batch->commit(); +} + #endif } // namespace sc diff --git a/sc/source/core/tool/formulalogger.cxx b/sc/source/core/tool/formulalogger.cxx index ff6964619024..3b12f09192b0 100644 --- a/sc/source/core/tool/formulalogger.cxx +++ b/sc/source/core/tool/formulalogger.cxx @@ -340,7 +340,9 @@ FormulaLogger::GroupScope FormulaLogger::enterGroup( // Get the file name if available. const SfxObjectShell* pShell = rDoc.GetDocumentShell(); const SfxMedium* pMedium = pShell->GetMedium(); - OUString aName = pMedium->GetURLObject().GetLastName(); + OUString aName; + if (pMedium) + aName = pMedium->GetURLObject().GetLastName(); if (aName.isEmpty()) aName = "-"; // unsaved document.