On 07/07/2013 01:18 PM, John Reiser wrote:
gcc tsvd3.o -o tsvd3 -l:/libHigh.so -l:/libblasB.a -l:/libblas.so -l:/liblapack.soI am using -l: rather than -l because I was using debug versions of libraries in different locations, but I was not able to get the debug-info packages to work in the intended seamless way. Removing either the High or blasB library ( or both) from the link line results in no errors being reported by valgrind. This raises the following questions: -- The High library is not being referenced by the tsvd3 executable, so why does the map file show that the blasB library is being used to resolve references in the High library?Consult the output from "readelf --dynamic tsvd3". Naming a .so shared library on the command line generates a [DT_]NEEDED entry in the Dynamic table of the executable, so that shared library is *required* at execution time. The .so is not optional, even if the .so satisfies no undefined references at static link time. At static link time (during the running of /bin/ld), any undefined symbols of the .so get added to the set which ld will try to satisfy. Thus ld will search for any symbols which are undefined in libHigh.so, and if some .o in libblasB.a defines such a symbol, then ld will load that .o from libblasB.a into tsvd3.-- In the above link line, the lapack library comes at the end. I thought that this would cause the lapack library not to see the blas symbols earlier in the link line i.e. the linker should be complaining about unresolved symbols. Why is the linker not so complaining?The search procedure for symbols which are undefined in shared library liblapack.so is an amalgamation of the [DT_]NEEDED entries within liblapack.so, the module tsvd3 (including its [DT_]NEEDED entries), any .a archive libraries that are specified on the command line at static link time, any -Rpath specifications, and the value of environment variable LD_LIBRARY_PATH. There are different rules between static link time and dynamic run time. Read the documentation carefully (info ld, man ld, etc.)-- Why is the linker not complaining about doubly defined symbols in the blasB.a and blas.so libraries?"Doubly defined" pertains only to within one module (main program or shared library.) Separate modules can have definitions of the same symbol without complaint. Which symbol gets used depends on the search path, and the search path depends scope rules at both static link time (/bin/ld) and run time (dynamic link time, ld-linux.so)Of course, how does all this trick valgrind into flagging uninitialized memory locations? The output of the svd3 program is correct with both versions of the tsvd3 executable.Construct the smallest example which causes trouble. Post it here. ------------------------------------------------------------------------------ This SF.net email is sponsored by Windows: Build for Windows Store. http://p.sf.net/sfu/windows-dev2dev _______________________________________________ Valgrind-users mailing list [email protected] https://lists.sourceforge.net/lists/listinfo/valgrind-users
Thank you for the helpful explanations. Attached are two C++ source files that illustrate the problem I have described. The build of the tsvd3 executable is: gcc -g -c gemv2.cpp gcc -g -c tsvd3.cpp gcc -g gemv2.o tsvd3.o -llapack -lblas -lstdc++ -o tsvd3 -Wl,-y,dgemv_ NOTES: 1) Rather than linking exactly as above, I used debug versions of lapack and blas so I could explore with gdb. 2) The output from the link tells about dgemv_ for this executable: gemv2.o: definition of dgemv_/usr/lib/gcc/i686-redhat-linux/4.7.2/../../../liblapack.so: reference to dgemv_ /usr/lib/gcc/i686-redhat-linux/4.7.2/../../../libblas.so: reference to dgemv_
The gemv2.cpp is a slash and contract of (some of) the very well written and organized source code of the FLENS numerical linear algebra package. My apologies to FLENS for having to distort their handiwork for this purpose :-). Initially, I had thought that fortran was initializing the memory, since the routine is called dgemv_, but it turns out I was using a FLENS option that implements this routine in C++, as in the atached gemv2.cpp . So, the fortran lapack and blas libraries are calling the C++ routine dgemv_. Might this be confusing to valgrind?? The running of tsvd3 gives the values: VS= 6.25801 4.91733 3.72567 2.98619 (I think these are not the correct singular values, but this is not relevant to valgrind issue) I ran valgrind: valgrind --track-origins=yes --fullpath-after= ./tsvd3 The first reported error is ==18263== Conditional jump or move depends on uninitialised value(s)==18263== at 0x433B99F: iladlr_ (/usr/src/debug/lapack-3.4.2/SRC/iladlr.f:107) ==18263== by 0x4287CEE: dlarf_ (/usr/src/debug/lapack-3.4.2/SRC/dlarf.f:187) ==18263== by 0x4202FC9: dgelq2_ (/usr/src/debug/lapack-3.4.2/SRC/dgelq2.f:184) ==18263== by 0x4203624: dgelqf_ (/usr/src/debug/lapack-3.4.2/SRC/dgelqf.f:262) ==18263== by 0x4216632: dgesdd_ (/usr/src/debug/lapack-3.4.2/SRC/dgesdd.f:1055) ==18263== by 0x8049559: main (/home/norm17b/dev/src/ssrd/test/lor/tsvd3.cpp:61)
==18263== Uninitialised value was created by a heap allocation==18263== at 0x4008449: operator new[](unsigned int) (/builddir/build/BUILD/valgrind-3.8.1/coregrind/m_replacemalloc/vg_replace_malloc.c:357) ==18263== by 0x80494BA: main (/home/norm17b/dev/src/ssrd/test/lor/tsvd3.cpp:52)
The line in main() that allocates the memory is
double* work = new double[ lwork ];
where
lwork= 300
This is a typical work array in the style of lapack.
Next, I stepped into iladr through the above chain, and set a breakpoint
at iladr.f:107
ELSE IF( A(M, 1).NE.ZERO .OR. A(M, N).NE.ZERO ) THEN
ILADLR = M
Examining memory,
p m
p n
p lda
x/Kfg &a
where K = lda * n
I found that the mxn submatrix was always initialized at all its
entries. I did this several times, until "gdb continue" resulted
in the program completing (because of looping, the breakpoint
re-occurred several times).
This is why I am puzzled as to why valgrind is reporting uninitialised
value(s).
#include <ctype.h> // toupper
enum Transpose {NoTrans=0, Conj=1, Trans=2, ConjTrans=3};
enum StorageOrder {
RowMajor,
ColMajor
};
#define conjugate(x) (x)
template <typename IndexType, typename ALPHA, typename Y>
void
scal_generic(IndexType n, const ALPHA &alpha, Y *y, IndexType incY)
{
for (IndexType i=0, iY=0; i<n; ++i, iY+=incY) {
y[iY] *= alpha;
}
}
template <typename IndexType, typename X, typename Y, typename Result>
void
dot_generic(IndexType n,
const X *x, IndexType incX, const Y *y, IndexType incY,
Result &result)
{
result = Result(0);
for (IndexType i=0, iX=0, iY=0; i<n; ++i, iX+=incX, iY+=incY) {
result += conjugate(x[iX])*y[iY];
}
}
template <typename IndexType, typename X, typename Y, typename Result>
void
dotu_generic(IndexType n,
const X *x, IndexType incX, const Y *y, IndexType incY,
Result &result)
{
result = Result(0);
for (IndexType i=0, iX=0, iY=0; i<n; ++i, iX+=incX, iY+=incY) {
result += x[iX]*y[iY];
}
}
template <typename IndexType, typename ALPHA, typename MA, typename VX,
typename BETA, typename VY>
void
gemv_generic(StorageOrder order, Transpose transA, Transpose conjX,
IndexType m, IndexType n,
const ALPHA &alpha,
const MA *A, IndexType ldA,
const VX *x, IndexType incX,
const BETA &beta,
VY *y, IndexType incY)
{
if (order==ColMajor) {
transA = Transpose(transA^Trans);
::gemv_generic(RowMajor, transA, conjX, n, m, alpha, A, ldA,
x, incX, beta, y, incY);
return;
}
if ((transA==NoTrans) || (transA==Conj)) {
if (incX<0) {
x -= incX*(n-1);
}
if (incY<0) {
y -= incY*(m-1);
}
scal_generic(m, beta, y, incY);
if (conjX==NoTrans) {
if (transA==Conj) {
for (IndexType i=0, iY=0; i<m; ++i, iY+=incY) {
VY _y;
dot_generic(n, A+i*ldA, IndexType(1), x, incX, _y);
y[iY] += alpha*_y;
}
} else {
for (IndexType i=0, iY=0; i<m; ++i, iY+=incY) {
VY _y;
dotu_generic(n, A+i*ldA, IndexType(1), x, incX, _y);
y[iY] += alpha*_y;
}
}
} else if (conjX==Conj) {
if (transA==Conj) {
for (IndexType i=0, iY=0; i<m; ++i, iY+=incY) {
VY _y;
dotu_generic(n, A+i*ldA, IndexType(1), x, incX, _y);
y[iY] += alpha*conjugate(_y);
}
} else {
for (IndexType i=0, iY=0; i<m; ++i, iY+=incY) {
VY _y;
dot_generic(n, x, incX, A+i*ldA, IndexType(1), _y);
y[iY] += alpha*_y;
}
}
}
} else {
if (incX<0) {
x -= incX*(m-1);
}
if (incY<0) {
y -= incY*(n-1);
}
scal_generic(n, beta, y, incY);
if (conjX==NoTrans) {
if (transA==ConjTrans) {
for (IndexType i=0, iY=0; i<n; ++i, iY+=incY) {
VY _y;
dot_generic(m, A+i, ldA, x, incX, _y);
y[iY] += alpha*_y;
}
} else {
for (IndexType i=0, iY=0; i<n; ++i, iY+=incY) {
VY _y;
dotu_generic(m, A+i, ldA, x, incX, _y);
y[iY] += alpha*_y;
}
}
} else if (conjX==Conj) {
if (transA==ConjTrans) {
for (IndexType i=0, iY=0; i<n; ++i, iY+=incY) {
VY _y;
dotu_generic(m, A+i, ldA, x, incX, _y);
y[iY] += alpha*conjugate(_y);
}
} else {
for (IndexType i=0, iY=0; i<n; ++i, iY+=incY) {
VY _y;
dot_generic(m, x, incX, A+i, ldA, _y);
y[iY] += alpha*_y;
}
}
}
}
}
template <typename IndexType, typename ALPHA, typename MA, typename VX,
typename BETA, typename VY>
void
gemv(StorageOrder order, Transpose trans,
IndexType m, IndexType n,
const ALPHA &alpha,
const MA *A, IndexType ldA,
const VX *x, IndexType incX,
const BETA &beta,
VY *y, IndexType incY)
{
if ((m==0) || (n==0)) {
return;
}
::gemv_generic(order, trans, NoTrans, m, n,
alpha, A, ldA, x, incX,
beta, y, incY);
}
////////////////////////////////////////////////////////////////
extern "C" {
void dgemv_( const char *TRANS,
const int *M,
const int *N,
const double *ALPHA,
const double *_A,
const int *LDA,
const double *X,
const int *INCX,
const double *BETA,
double *Y,
const int *INCY)
{
Transpose trans;
switch( toupper(*TRANS) )
{
case 'T': { trans = Trans; break; }
case 'C': { trans = ConjTrans; break; }
case 'R': { trans = Conj; break; }
default: { trans = NoTrans; break; }
}
const bool noTrans = (trans==NoTrans || trans==Conj);
int lenX, lenY;
if (noTrans) {
lenX = *N;
lenY = *M;
} else {
lenX = *M;
lenY = *N;
}
::gemv( ColMajor,
trans,
*M, *N,
*ALPHA,
_A, *LDA,
X, *INCX,
*BETA,
Y, *INCY );
}
} // extern "C"
#include <iostream>
using namespace std;
extern "C" {
void
dgesdd_(const char *JOBZ,
const int *M,
const int *N,
double *A,
const int *LDA,
double *S,
double *U,
const int *LDU,
double *VT,
const int *LDVT,
double *WORK,
const int *LWORK,
int *IWORK,
int *INFO);
}
int main()
{
double VS[4];
double MU[16];
double MA2[] = {
-3.034994, -0.511282, 2.082734, -0.254566, 0.640815, -1.461910, 1.901411, 4.607602,
0.164566, -2.989098, 0.163304, -1.536114, -0.988787, 1.990146, -0.822878, 2.981577,
-0.684081, -0.328423, 0.581347, 0.538591, -1.153259, 0.040544, -2.502355, 0.202044,
-1.025186, -1.745052, -0.585212, -1.660798, -0.151452, 1.451067, -0.237470, -0.893914 };
char jobz = 'O';
int m = 4;
int n = 8;
int lwork = -1;
double lwork_q = 0;
int* iwork = new int[ 8*m ];
int info = -1;
// The first call is just to set the value of lwork_q
dgesdd_( &jobz, &m, &n, MA2, &m, VS,
MU, &m, NULL, &m,
&lwork_q, &lwork, iwork, &info );
cout << "lwork_q= " << lwork_q << endl;
lwork = int( lwork_q );
cout << "lwork= " << lwork << endl;
double* work = new double[ lwork ];
// Elliminate spurious valgrind uninitialized errors
#if 0
for( int iii=0; iii<lwork; ++iii ) work[iii]=123.456;
#endif
dgesdd_( &jobz, &m, &n, MA2, &m, VS,
MU, &m, NULL, &m,
work, &lwork, iwork, &info );
delete [] work;
delete [] iwork;
cout << "VS=";
for( int iii2 = 0; iii2 < 4; ++iii2 ) cout << " " << VS[iii2];
cout << endl;
return 0;
}
smime.p7s
Description: S/MIME Cryptographic Signature
------------------------------------------------------------------------------ This SF.net email is sponsored by Windows: Build for Windows Store. http://p.sf.net/sfu/windows-dev2dev
_______________________________________________ Valgrind-users mailing list [email protected] https://lists.sourceforge.net/lists/listinfo/valgrind-users
