Eigen Simplicial LDLT Performance for Sparse Linear Systems - c++

I've been using Eigen for a while, albeit probably pretty poorly. The reason I say this is because I can't seem to achieve the performance that others are achieving from the library. I've scoured the forums and dark corners of the internet trying to find solutions to why I cannot seem to achieve great performance, so asking here and hoping that someone can help. Be aware that I don't have much experience with C++ and proper ways of including Eigen. Currently I have simply copied the Eigen source into my project directory and included the folder in my include paths. My project is in Visual Studio 2019.
But on to the problem. I have some reasonably sized sparse linear systems for which I'm trying to solve A*x = b, where A is sparse (typically 0.05% or far less) and can be anywhere from 10x10 to 400,000x400,000, or larger. 'A' is symmetric positive definite. The 'b' vector is typically fairly dense, but can be sparse on occasion.
As a benchmark, I have a problem that is approximately 100,000x100,000. I am pre-conditioning prior to solving potentially numerous 'b' vectors with the same 'A' matrix. Preconditioning takes approximately 6s. Solving takes another 0.5 seconds per 'b' vector. I'm seeing lots of people with problems just as large solving in 0.2 seconds (total, including preconditioning). So what am I doing wrong?
My code for preconditioning is:
SimplicialLDLT<SparseMatrix<double>>* SimplicialLDLT_Preconditioner(SparseMatrix<double>*ptr)
{
SimplicialLDLT<SparseMatrix<double>, Eigen::Lower, AMDOrdering<int>>* solver = new SimplicialLDLT<SparseMatrix<double>, Eigen::Lower, AMDOrdering<int>>();
solver->compute(*ptr);
if (solver->info() != Eigen::ComputationInfo::Success)
{
return nullptr;
}
return solver;
}
My code for solving is:
double* SimplicialLDLT_Solve(SimplicialLDLT<SparseMatrix<double>>* solverPtr, double* f, int numRows)
{
VectorXd f2(numRows);
for (int i = 0; i < numRows; i++)
{
f2[i] = f[i];
}
VectorXd x;
x = solverPtr->solve(f2).eval();
if (solverPtr->info() != Eigen::ComputationInfo::Success)
{
return nullptr;
}
int z = x.rows();
double* x_array = new double[z];
for (int i = 0; i < z; i++)
{
x_array[i] = x[i];
}
return x_array;
}
Based on all of the samples I've seen, I'm doing the same.
My compiler flags (in Microsoft Visual Studio 2019) are:
/Yu"stdafx.h" /GS /Qpar /GL /W3 /Gy /Zc:wchar_t /Zi /Gm- /O2 /Ob2 /Fd"obj\x64\Release\vc142.pdb" /Zc:inline /fp:precise /D "WIN32" /D "_WINDOWS" /D "NDEBUG" /D "_USRDLL" /D "NATIVEEIGENWRAPPER_EXPORTS" /D "NOMINMAX" /D "_WINDLL" /D "_UNICODE" /D "UNICODE" /errorReport:prompt /WX- /Zc:forScope /arch:SSE2 /Gd /Oi /MD /openmp /FC /Fa"obj\x64\Release\" /EHsc /nologo /Fo"obj\x64\Release\" /Ot /Fp"obj\x64\Release\myProj.pch" /diagnostics:column
Any insights would be much appreciated. Thanks!
UPDATE #1:
Tried switching compilers to g++ to see if that would help, given that I've read that VS C++ compiler is not fantastic for optimizing. I used the following compiler flags:
-Wa,-mbig-obj -O2 -mavx2 -mfma -finline-limit=1000000 -ffp-contract=fast -march=native -funroll-loops -fopenmp -DNDEBUG
I received maybe a 5% increase in speed, but nothing that I would call significant.
Running another benchmark problem that is approximately 200,000x200,000. Takes approximately 3.5 minutes to precondition using SimplicialLDLT. Matrix is 0.048% filled (so quite sparse) and SPD.

Related

Visual Studio 2013 not displaying unreferenced variable warnings

I am building in Visual Studio 2013, and if I add unreferenced variables to functions, the compiler does not throw warnings about them. I tried enabling code analysis, per this thread:
Visual Studio 2013 Compiler Warnings not Showing
but that still did not fix my issue. Some additional information:
I have the warning level set to 3 (/W3), am treating warning as errors (/WX), and am in a debug build with no optimization enabled.
My full command line from Project -> Properties -> Configuration Properties -> C/C++ -> Command Line is:
/GS /analyze- /W3 /Zc:wchar_t /ZI /Gm /Od /Fd"generated\debug\intermediate\vc120.pdb" /fp:precise /D "WIN32" /D "GLEW_STATIC" /D "_DEBUG" /D "_WINDOWS" /D "_VC80_UPGRADE=0x0710" /D "_MBCS" /errorReport:prompt /WX /Zc:forScope /RTC1 /Gd /Oy- /MTd /Fa"generated\debug\intermediate\" /EHsc /nologo /Fo"generated\debug\intermediate\" /Fp"generated\debug\intermediate\blahDebug.pch"
I'm iterating on a function that I'm constantly debugging, stepping through the code, etc. -- so I know the code is being run. But if I toss "int blah = 1;" in the function and recompile, no warnings are generated.
Example code:
bool MyClass::doSomething(int someParameter)
{
int blah = 1;
// run the normal function logic here
// 'someParameter' is referenced, but 'blah' never is.
// when i compile, i receive no warning that 'blah' is unreferenced.
return true;
}
In your example code, the statement int blah = 1; both declares the variable and assigns to it. Visual Studio counts this assignment as a "reference" of the variable, thus avoiding the C4101 unreferenced local variable error that you are expecting.
To locate and remove variables which are initialized but never used, you can use a static analysis tool such as Prefast or CppCheck. There is a list of such tools here, though it may be out of date.
Note that the compiler can flag unused parameters, even if they are initialized with a default parameter. If you use warning level 4 via /W4 or /Wall, then an unused parameter will cause a C4100 unreferenced parameter warning. It is a very good idea to always build at /W4 or /Wall, rather than the default /W3.
As Ryan Bemrose outlined, static code analysis tools can be used to detect unused resources from source code.
Take a look at following function:
bool foo(int unusedParameter)
{
int unusedVariable = 1;
return true;
}
It contains two unused resources, an unused parameter and and unused but initialized local variable. Cppcheck can assist you to detect unused local variables, by using the following command:
$ cppcheck --enable=all test.cpp
Checking test.cpp...
[test.cpp:3]: (style) Variable 'unusedVariable' is assigned a value that is never used.
Currently it does not detect unused parameters.

Visual Studio 2013 doesn't ignore disabled warnings

Good morning all. So I'm attempting to disable Warning 4996 in our c++ projects. It seems to be included in the command line as shown below, but upon compiling, still pops up with the C4966 Warning. I've tried changing the warning level to 3, or using /w44996, but neither have worked. Does anyone know why this might be?
/Yu"stdafx.h" /GS- /W4 /wd"4100" /wd"4121" /wd"4201" /wd"4214" /wd"4244" /wd"4996" /Zc:wchar_t /I"C:\Program Files (x86)\MSBuild\..\Common Files\Microsoft Shared\MSEnv" /I"C:\Program Files (x86)\MSBuild\..\Common Files\Designer" /I"D:\Workspaces\MST_Sustaining_Second\Inc" /I"D:\Workspaces\MST_Sustaining_Second\Develop\Shared\Include" /Zi /Gm /Od /Fd"D:\Workspaces\MST_Sustaining_Second\Develop\IDE\GrACE\Debug\vc120.pdb" /fp:precise /D "_USRDLL" /D "ACE_DLL" /D "IQEDITOR_ENABLED" /D "_WINDOWS" /D "_DEBUG" /D "NTDDI_VERSION=NTDDI_WIN7" /D "_WIN32_WINNT=0x0601" /D "WINVER=0x0601" /D "_AFXDLL" /D "WIN32" /D "_SECURE_SCL=0" /D "_WINDLL" /D "_MBCS" /errorReport:prompt /GF- /WX- /Zc:forScope /RTC1 /Gd /Oi /MDd /Fa"D:\Workspaces\MST_Sustaining_Second\Develop\IDE\GrACE\Debug\" /EHs /nologo /Fo"D:\Workspaces\MST_Sustaining_Second\Develop\IDE\GrACE\Debug\" /Fp"D:\Workspaces\MST_Sustaining_Second\Develop\IDE\GrACE\Debug\ace.pch"
EDIT: Typo in description. I do mean Warning 4996, not 4966. 4996 is in the command line as /wd"4996"
For Warning:
warning C4996: 'MBCS_Support_Deprecated_In_MFC': MBCS support in MFC is deprecated and may be removed in a future version of MFC.
It looks like #pragma warning(disable: 4996) will not disable the MBCS deprecation warning due to the
#pragma warning(1: 4996) before the _declspec(deprecated) line in afx.h
For obscure reasons, you must use #define NO_WARN_MBCS_MFC_DEPRECATION to disable this instead.
see afx.h lines 28-33
#ifndef NO_WARN_MBCS_MFC_DEPRECATION
#ifdef _MBCS
// Warn about MBCS support being deprecated: see http://go.microsoft.com/fwlink/p/?LinkId=279048 for more information.
#pragma warning(push)
#pragma warning(1 : 4996)
inline __declspec(deprecated("MBCS support in MFC is deprecated and may be removed in a future version of MFC.")) void MBCS_Support_Deprecated_In_MFC() { }
In order to Pat Brenner (Visual C++ Libraries Development Team) mentioned in his blog ,
we are deprecating MBCS support in MFC for Visual Studio 2013. This
keeps MFC more closely aligned with the Windows SDK itself, because
many of the newest controls and messages are Unicode only
This warning can be eliminated by adding the
NO_WARN_MBCS_MFC_DEPRECATION preprocessor definition to your project
build definitions.
Then do this.
Go to Project Properties-> C\C++ ->Preprocessor->Preprocessor Definition and add NO_WARN_MBCS_MFC_DEPRECATION
I have had a similar issue but it was on some functions from io.h and string.h such as these:
source.cxx(713) : warning C4996: 'stricmp': The POSIX name for this item is deprecated. Instead, use the ISO C++ conformant name: _stricmp. See online help for details.
C:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\include\string.h(215) : see declaration of 'stricmp'
source.cxx(2416) : warning C4996: 'strdup': The POSIX name for this item is deprecated. Instead, use the ISO C++ conformant name: _strdup. See online help for details.
C:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\include\string.h(207) : see declaration of 'strdup'
source.cxx(2249) : warning C4996: 'isatty': The POSIX name for this item is deprecated. Instead, use the ISO C++ conformant name: _isatty. See online help for det
ails.
Due to the need to have the exact same code run be built on other platforms, I had to find a solution without fiddling much in code as this occurred all over the project in a lot of files.
The solution was to add this compiler flag _CRT_NONSTDC_NO_DEPRECATE. This can be done in one of two ways:
Passing -D_CRT_NONSTDC_NO_DEPRECATE if you are using the cl command directly
Or from Visual Studio GUI if you use it for the building process. Add _CRT_NONSTDC_NO_DEPRECATE in Project Properties > C\C++ > Preprocessor > Preprocessor Definition

While loop not checking condition if there are no statements

This shouldn't be too hard to understand:
bool ThreadIsRunning = false;
void Thread1(void *nothing){
ThreadIsRunning = true;
cout << "The thread is running!\n";
Sleep(1000);
cout << "Ending thread!\n");
ThreadIsRunning = false;
_endthread();
return;
}
int main(){
std::cout << "The thread is starting!\n";
_beginthread(Thread1, 0, 0);
std::cout << "Waiting for thread to end!\n";
while(ThreadIsRunning);
std::cout << "The thread is ended!\n";
return 0;
}
So the main thread wait's for the Thread1 to set ThreadIsRunning to false, right?
Yeah, but it does not. Nothing happens when it goes to false. Shouldn't it check the value for eternity until it's changed?
It works if I put while(ThreadIsRunning) Sleep(10); but I don't think it should be necessary for my code to work.
while(ThreadIsRunning) void(); does not work either.
Im using Visual Studio Ultimate 2012.
C/C++ command line options:
/GS /GL /analyze- /W3 /Gy /Zc:wchar_t /Zi /Gm- /O2 /sdl /Fd"Release\vc110.pdb" /fp:precise /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_UNICODE" /D "UNICODE" /errorReport:prompt /WX- /Zc:forScope /Gd /Oy- /Oi /MD /Fa"Release\" /EHsc /nologo /Fo"Release\" /Fp"Release\Test1.pch"
Linker command line options:
/OUT:"<projectsfolder>\Test1\Release\Test1.exe" /MANIFEST /LTCG /NXCOMPAT /PDB:"<projectsfolder>\Test1\Release\Test1.pdb" /DYNAMICBASE "kernel32.lib" "user32.lib" "gdi32.lib" "winspool.lib" "comdlg32.lib" "advapi32.lib" "shell32.lib" "ole32.lib" "oleaut32.lib" "uuid.lib" "odbc32.lib" "odbccp32.lib" /DEBUG /MACHINE:X86 /OPT:REF /SAFESEH /INCREMENTAL:NO /PGD:"<projectsfolder>\Test1\Release\Test1.pgd" /SUBSYSTEM:CONSOLE /MANIFESTUAC:"level='asInvoker' uiAccess='false'" /ManifestFile:"Release\Test1.exe.intermediate.manifest" /OPT:ICF /ERRORREPORT:PROMPT /NOLOGO /TLBID:1
Edit:
There is NOT a schedule/race/time problem. Even if I add Sleep(1000); after _beginthread(Thread1, 0, 0), the problem is still that nothing happens when ThreadIsRunning goes to false
This can be down to the thread scheduling - it is perfectly possible that before the thread even starts that the thread running main() reaches your while() statement and breaks out of it before the thread has had chance to change your global boolean to true. That is probably why you see that adding the Sleep call give the thread chance to change from false to true and you see the behaviour you expect.
C++03 is not a thread-aware language and the optimizer can "clearly see" (having no knowledge that another thread could be changing it) that ThreadIsRunning is not changing during the loop body. As soon as you add the call to sleep the compiler has to assume that sleep accesses an aliased copy of ThreadIsRunning and has to check its value each iteration through the loop.
The solution to your problem is to not use a standard variable and a wait-loop (which will pet a CPU core). Instead use a condition variable and signal between thread when appropriate, as that's the standard way to convey such information between threads.
The problem is that the compiler feels free to hoist the load of the variable ThreadIsRunning out of the loop -- loading it once before the loop into a register and then checking the register (instead of the variable) each time around the loop. The register never becomes false, so the loop never exits.
The easiest and most obvious fix is to mark the variable volatile. That way, the compiler knows it can't hosit the load, and needs to reload the variable each time around the loop.
Another "fix" that makes things work is to call any externally defined function in the loop (such as Sleep). Since the compiler doesn't know what Sleep does, it must assume it might change the global var, so it needs to be reloaded. Calling a local function (one defined earlier in the same file or a header) probably won't work, because then the compiler knows what the function does (and in particular that it doesn't modify ThreadIsRunning)
You may have to declare ThreadIsRunning as volatile. The compiler probably optimized it out since it did not see anything modifying it in main().
Add ThreadIsRunning = true; just before starting the thread:
std::cout << "The thread is starting!\n";
ThreadIsRunning = true; // <============= add this
_beginthread(Thread1, 0, 0);
// etc.
That will tell you if it's a scheduling problem (which is likely).

Embed POCO static library into another one

I'm developing an SDK (as dynamic and static lib) using Poco, and I would like to embed the Poco static libs into my one to avoid the end user to setup and link the Poco enviroment.
The C/C++ settings for the MySDKd.LIB are:
/I"..\..\..\include"
/I"..\..\..\src"
/I"D:\lib\boost_1_53_0\"
/I"..\..\..\thirdparty"
/I"..\..\..\thirdparty\protobuf\include\"
/ZI /nologo /W3 /WX- /Od /Oy-
/D "WIN32" /D "_DEBUG" /D "_LIB"
/D "WIN32_LEAN_AND_MEAN" /D "_MBCS"
/D "POCO_STATIC" /D "POCO_NO_AUTOMATIC_LIBS"
/D "IBPP_WINDOWS"
/Gm /EHa /RTC1 /MDd /GS /fp:precise /Zc:wchar_t /Zc:forScope
/Fp"Debug\MySDKd.pch" /Fa"Debug\" /Fo"Debug\" /Fd"Debug\vc100.pdb"
/Gd /analyze- /errorReport:queue
And the linker settings are:
/OUT:"D:\src\MySDK\win32\VS2010\..\..\..\bin\static\MySDKd.lib"
"libprotobufd.lib"
"PocoFoundationmdd.lib"
"PocoUtilmdd.lib"
"PocoNetmdd.lib"
"PocoXMLmdd.lib"
/LIBPATH:"D:\lib\boost_1_53_0\stage\lib"
/LIBPATH:"D:\lib\poco-1.5.1-all\lib"
/LIBPATH:"D:\src\MySDK\lib"
/NOLOGO /NODEFAULTLIB
Now, when I build a simple test project (which use the sdk), I get the linker error:
LINK : fatal error LNK1104: cannot open file 'PocoFoundationmdd.lib'
unless I add to the linker path of my test project the Poco\lib folder.
But this lib should now be a part of my MySDKd.lib, right?
When I build my SDK, moreover, I get this linker warning:
PocoFoundationmdd.lib(ByteOrder.obj) : warning LNK4221: This object file does not define any previously undefined public symbols, so it will not be used by any link operation that consumes this library
PocoFoundationmdd.lib(String.obj) : warning LNK4221: This object file does not define any previously undefined public symbols, so it will not be used by any link operation that consumes this library
PocoFoundationmdd.lib(SignalHandler.obj) : warning LNK4221: This object file does not define any previously undefined public symbols, so it will not be used by any link operation that consumes this library
PocoFoundationmdd.lib(WS2_32.dll) : warning LNK4006: __NULL_IMPORT_DESCRIPTOR already defined in PocoFoundationmdd.lib(IPHLPAPI.DLL); second definition ignored
PocoFoundationmdd.lib(WS2_32.dll) : warning LNK4221: This object file does not define any previously undefined public symbols, so it will not be used by any link operation that consumes this library
PocoXMLmdd.lib(XMLString.obj) : warning LNK4221: This object file does not define any previously undefined public symbols, so it will not be used by any link operation that consumes this library
Searching around, I found this article (see the section 'Build a static library with other static libraries') but referring to this case, I don't understand why this happen.
Is this warning may be the cause to my problem?
Regards,
Daniele
I may be wrong but did you put *.lib file into your project D:\src\MySDK\win32\VS2010 if not than put them into your project.
It seems that feature was changed in VS 2010. What you are trying to do seems not to work since VS 2010. See this question and related MSDN blog for more details. I have no first hand experience with it, but make-it-so provides a tool that allegedly can do what you're trying to do.

Visual Studio Compiler Default for /O

Does VS2010/12's compiler use a default optimization level when none of /Od,/O1,/O2,/Ox is provided in a C++ compilation command line?
I'm currently using /Od since I witnessed some optimization related bugs when using the other levels. However, this leads to /GS being disabled - which is unwanted.
When I clear the box for the "Project Properties->C/C++->Optimization->Optimization" option, I see the command line indeed doesn't contain any option. But I don't know if this just means the compiler uses some default optimization level.
No optimization seems to be the default - see output from "cl /?" below:
-OPTIMIZATION-
/O1 minimize space /O2 maximize speed
/Ob<n> inline expansion (default n=0) /Od disable optimizations (default)
/Og enable global optimization /Oi[-] enable intrinsic functions
/Os favor code space /Ot favor code speed
/Ox maximum optimizations /Oy[-] enable frame pointer omission