I'm trying to compile MIPS32 code in a virtual machine. The rest of the program is done in C code.
Here the problematic code:
"# include "ordenamiento.h"
"# a0 is the pointer to char **, a1 is the start (int), a2 is the end (int)
.overall stoogeSort
.Set noreorder
.cpload $t9
.September reorder
.cprestore
.ent stoogeSort
"#arming the stack
stoogeSort:
addiu $ sp, -32
sw $ fp, 28 ($ sp)
$ sw gp, 24 ($ sp)
move $ fp, $ sp
sw $ a0, 32 ($ sp)
sw $ a1, 36 ($ sp)
sw $ a2, 40 ($ sp)
b CMP
FinComp: bgt $ t0, $ zero, noswap
Swap: addu $ t2, $ a0, $ a1
----
----
----
. stoogeSort end
The problem is that when compiling as follows gcc-c-O0 stoogeSort.S gives me the following errors:
stooge.s: 1: Warning: line numbers must be positive, line number 0 rejected
stooge.s: 9: Error: illegal operands `sw $ a0, 32 ($ sp) '
stooge.s: 10: Error: illegal operands `sw $ a1, 36 ($ sp) '
stooge.s: 11: Error: illegal operands `sw $ a2, 40 ($ sp) '
stooge.s: 12: Error: unrecognized opcode `ba CMP '
stooge.s: 13: Error: illegal operands `bgt $ t0, $ zero, noswap '
stooge.s: 14: Error: illegal operands `addu $ t2, $ a0, $ a1 '
stooge.s: 15: Error: illegal operands `addu $ t3, $ a0, $ a2 '
What am I doing wrong? Why do I get these errors?
Since you have got an answer to your question, its better to post it here so that its going to be helpful for those who come here with the same problem.
I am posting the answer here for you.
The problem was the missing "# include <mips/regdef.h>"
Related
Question
I am trying to generate random numbers with OpenACC and the cuRAND library. I have a simple piece of code (just trying a few things), which is basically a copy from the pgi cuRAND examples (/opt/pgi/linux86-64/2018/examples/CUDA-Libraries/cuRAND).
The problem is that I run into an error: undefined reference to ``__pgicudalib_curandInitXORWOW' and undefined reference to ``__pgicudalib_curandUniformXORWOW'.
Those are declared in the openacc_curand.h file:
#define curand_init __pgicudalib_curandInitXORWOW
#define curand_uniform __pgicudalib_curandUniformXORWOW
#pragma acc routine(__pgicudalib_curandInitXORWOW) seq
extern void __pgicudalib_curandInitXORWOW(unsigned long long, unsigned long long, unsigned long long, curandStateXORWOW_t *);
#pragma acc routine(__pgicudalib_curandUniformXORWOW) seq
extern float __pgicudalib_curandUniformXORWOW(curandStateXORWOW_t *);
This is the source code:
openacc-test.cpp
#include <openacc.h>
#include <array>
#include "openacc_curand.h"
constexpr int SIZE = 16;
std::array<float, SIZE> data;
float* d_data;
void init(int x){
for(int i = 0; i < SIZE; ++i){
data[i] = x;
}
}
void print(){
printf("Host: [");
for(int i = 0; i < SIZE; ++i){
printf("data: %.5f; ", data[i]);
}
printf("]\n");
}
void do_stuff_on_gpu(){
unsigned long long seed;
unsigned long long seq;
unsigned long long offset;
curandState_t state;
#pragma acc parallel deviceptr(d_data) private(state)
{
seed = 12345ULL;
seq = 0ULL;
offset = 0ULL;
curand_init(seed, seq, offset, &state);
#pragma acc loop seq
for(int i = 0; i < SIZE; ++i){
d_data[i] = curand_uniform(&state);
}
}
}
int main(int argc, char** argv) {
d_data = static_cast<float*>(acc_malloc(SIZE * sizeof(float)));
init(42.17f);
print();
acc_map_data( data.data(), d_data, SIZE * sizeof(float));
acc_update_device(data.data(), SIZE * sizeof(float));
do_stuff_on_gpu();
print();
acc_update_self(data.data(), SIZE * sizeof(float));
print();
acc_free(d_data);
return EXIT_SUCCESS;
}
This is the cmake file:
cmake_minimum_required(VERSION 3.10)
project(openacc-test VERSION 1.0.0 LANGUAGES CXX)
SET( CMAKE_CXX_FLAGS_DEV "-g -O0 -Minfo=accel -ta=tesla,nollvm -Mcudalib=curand" )
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/bin")
find_package(OpenACC REQUIRED)
add_executable(openacc-test ${PROJECT_SOURCE_DIR}/src/openacc-test.cpp)
target_compile_features(openacc-test PRIVATE cxx_std_14)
target_include_directories(openacc-test PRIVATE ${PROJECT_SOURCE_DIR}/include)
target_compile_options(openacc-test PRIVATE ${OpenACC_CXX_FLAGS})
target_link_libraries(openacc-test PRIVATE ${OpenACC_CXX_FLAGS} -lcurand -L/opt/pgi/linux86-64/2018/cuda/10.0/lib64)
And I build it like this from the build folder:
cmake -G "Unix Makefiles" -D CMAKE_BUILD_TYPE=Dev -D CMAKE_CXX_COMPILER=pgc++ ../ && \
make openacc-test && \
bin/openacc-test
Since there are undefined reference errors I guess there is something wrong with the linking process. I used -ta=tesla,nollvm -Mcudalib=curand flags for pgi and manually set the path to the cuda libraries -lcurand -L/opt/pgi/linux86-64/2018/cuda/10.0/lib64. I also tried the findCuda module and the nativa Cuda support in CMake, but both don't seem to work. Any idea what is wrong here?
Edits:
Fixed the syntax according to Mat's answer, but the error is still there.
If I build from the command line, I get the following output:
pgc++ -v -fast -ta=tesla:nollvm --c++11 -Minfo=accel openacc-test.cpp
Export PGI_CURR_CUDA_HOME=/opt/pgi/linux86-64/2018/cuda/10.0
Export PGI=/opt/pgi
/opt/pgi/linux86-64/18.10/bin/pggpp1 --llalign -Dunix -D__unix -D__unix__ -Dlinux -D__linux -D__linux__ -D__NO_MATH_INLINES -D__LP64__ -D__x86_64 -D__x86_64__ -D__LONG_MAX__=9223372036854775807L '-D__SIZE_TYPE__=unsigned long int' '-D__PTRDIFF_TYPE__=long int' -D__extension__= -D__amd_64__amd64__ -D__k8 -D__k8__ -D__SSE__ -D__MMX__ -D__SSE2__ -D__SSE3__ -D__SSE4A__ -D__ABM__ -D__PGI -D_GNU_SOURCE -D_PGCG_SOURCE -I- -I/opt/pgi/linux86-64/18.10/include-gcc70 -I/opt/pgi/linux86-64/18.10/include -I/usr/include/c++/7 -I/usr/include/x86_64-linux-gnu/c++/7 -I/usr/include/c++/7/backward -I/usr/lib/gcc/x86_64-linux-gnu/7/include -I/usr/local/include -I/usr/lib/gcc/x86_64-linux-gnu/7/include-fixed -I/usr/include/x86_64-linux-gnu -I/usr/include -I/opt/pgi/linux86-64/2018/cuda/10.0/include -D_ACCEL=201003 -D_OPENACC=201711 -D__CUDA_API_VERSION=10000 -DPGI_TESLA_TARGET --preinclude _cplus_preinclude.h --preinclude_macros _cplus_macros.h --gnu_version=70300 -D__pgnu_vsn=70300 --accel --preinclude openacc_predef.h --c++11 -q -o /tmp/pgc++-YTc9tfiZkMv.il openacc-test.cpp
/opt/pgi/linux86-64/18.10/bin/pggpp2 openacc-test.cpp -opt 2 -x 119 0xa10000 -x 122 0x40 -x 123 0x1000 -x 127 4 -x 127 17 -x 19 0x400000 -x 28 0x40000 -x 120 0x10000000 -x 70 0x8000 -x 122 1 -x 125 0x20000 -quad -vect 56 -y 34 16 -x 34 0x8 -x 32 6291456 -y 19 8 -y 35 0 -x 42 0x30 -x 39 0x40 -x 199 10 -x 39 0x80 -x 59 4 -tp shanghai -x 120 0x1000 -astype 0 -x 121 1 -fn openacc-test.cpp -il /tmp/pgc++-YTc9tfiZkMv.il -x 117 0x600 -x 123 0x80000000 -x 123 4 -x 119 0x20 -def __pgnu_vsn=70300 -autoinl 10 -x 168 400 -x 174 128000 -x 14 0x200000 -x 46 4 -x 14 0x400000 -x 120 0x200000 -x 70 0x40000000 -x 164 0x800000 -accel tesla -x 180 0x4000400 -x 121 0xc00 -x 186 0x80 -x 163 0x1 -x 186 0x80000 -cudaver 10000 -x 194 0x40000 -y 189 0x10 -cudaroot /opt/pgi/linux86-64/2018/cuda/10.0 -x 176 0x100 -cudacap 60 -x 189 0x8000 -y 163 0xc0000000 -y 189 0x4000000 -cudaroot /opt/pgi/linux86-64/2018/cuda/10.0 -x 9 1 -x 42 0x14200000 -x 72 0x1 -x 136 0x11 -quad -x 119 0x10000000 -x 129 0x40000000 -x 129 2 -x 164 0x1000 -x 0 0x1000000 -x 2 0x100000 -x 0 0x2000000 -x 161 16384 -x 162 16384 -gnuvsn 70300 -x 69 0x200 -cmdline '+pgc++ /tmp/pgc++-YTc9tfiZkMv.il -v -fast -Mvect=sse -Mcache_align -Mflushz -Mpre -ta=tesla:nollvm --c++11 -Minfo=accel' -asm /tmp/pgc++3YTcLZpe7Hgh.s
do_stuff_on_gpu():
93, Accelerator kernel generated
Generating Tesla code
99, #pragma acc loop seq
93, CUDA shared memory used for state
/opt/pgi/linux86-64/18.10/bin/pgnvd -dcuda /opt/pgi/linux86-64/2018/cuda/10.0 -reloc /tmp/pgacc62TcUtvwk7F_.gpu -computecap=60 -ptx /tmp/pgaccA2Tco99QQ3zu.ptx -o /tmp/pgaccQ2Tc_MT360Ow.bin -ftz -cuda10000
/usr/lib/gcc/x86_64-linux-gnu/7/include/stddef.h(444): error: identifier "nullptr" is undefined
/usr/lib/gcc/x86_64-linux-gnu/7/include/stddef.h(444): error: expected a ";"
/usr/include/x86_64-linux-gnu/c++/7/bits/c++config.h(235): error: expected a ";"
/usr/include/c++/7/bits/exception.h(63): error: expected a ";"
/usr/include/c++/7/bits/exception.h(69): error: expected a ";"
/usr/include/c++/7/exception(49): error: expected a ";"
/usr/include/c++/7/exception(57): error: expected a ";"
/usr/include/c++/7/exception(67): error: expected a "{"
/usr/include/c++/7/bits/cxxabi_init_exception.h(63): error: expected a "{"
/usr/include/c++/7/typeinfo(99): error: expected a ";"
/usr/include/c++/7/typeinfo(187): error: not a class or struct name
/usr/include/c++/7/typeinfo(190): error: expected a ";"
/usr/include/c++/7/typeinfo(197): error: expected a ";"
/usr/include/c++/7/typeinfo(204): error: not a class or struct name
/usr/include/c++/7/typeinfo(207): error: expected a ";"
/usr/include/c++/7/typeinfo(214): error: expected a ";"
/usr/include/c++/7/bits/exception_ptr.h(63): error: function "__cxxabiv1::std::current_exception" returns incomplete type "__cxxabiv1::std::__exception_ptr::exception_ptr"
/usr/include/c++/7/bits/exception_ptr.h(63): error: expected a "{"
/usr/include/c++/7/bits/exception_ptr.h(73): error: namespace "__cxxabiv1::std" has no member "rethrow_exception"
/usr/include/c++/7/bits/exception_ptr.h(83): error: expected a ";"
/usr/include/c++/7/bits/exception_ptr.h(85): error: expected a ";"
/usr/include/c++/7/bits/exception_ptr.h(86): error: expected a ";"
/usr/include/c++/7/bits/exception_ptr.h(88): error: expected a ";"
/usr/include/c++/7/bits/exception_ptr.h(90): error: declaration is incompatible with previous "__cxxabiv1::std::current_exception"
(63): here
/usr/include/c++/7/bits/exception_ptr.h(90): error: use of a local type to declare a function
/usr/include/c++/7/bits/exception_ptr.h(90): error: expected a ";"
/usr/include/c++/7/bits/exception_ptr.h(91): error: use of a local type to declare a function
/usr/include/c++/7/bits/exception_ptr.h(93): error: namespace "__cxxabiv1::std" has no member "make_exception_ptr"
/usr/include/c++/7/bits/exception_ptr.h(93): error: a template friend declaration cannot be declared in a local class
/usr/include/c++/7/bits/exception_ptr.h(93): error: expected a ";"
/usr/include/c++/7/bits/exception_ptr.h(96): error: expected a ";"
/usr/include/c++/7/bits/exception_ptr.h(98): error: expected a ";"
/usr/include/c++/7/bits/exception_ptr.h(101): error: incomplete type is not allowed
/usr/include/c++/7/bits/exception_ptr.h(101): error: expected a ";"
/usr/include/c++/7/bits/exception_ptr.h(122): error: expected a ";"
/usr/include/c++/7/bits/exception_ptr.h(132): error: expected a ";"
/usr/include/c++/7/bits/exception_ptr.h(149): error: use of a local type to declare a function
/usr/include/c++/7/bits/exception_ptr.h(150): error: expected a ";"
/usr/include/c++/7/bits/exception_ptr.h(153): error: expected a ";"
/usr/include/c++/7/bits/exception_ptr.h(158): error: use of a local type to declare a function
/usr/include/c++/7/bits/exception_ptr.h(159): error: expected a ";"
/usr/include/c++/7/bits/exception_ptr.h(162): error: use of a local type to declare a function
/usr/include/c++/7/bits/exception_ptr.h(163): error: expected a ";"
/usr/include/c++/7/bits/exception_ptr.h(166): error: use of a local type to declare a function
/usr/include/c++/7/bits/exception_ptr.h(167): error: expected a ";"
/usr/include/c++/7/bits/exception_ptr.h(179): error: expected a ";"
/usr/include/c++/7/bits/exception_ptr.h(220): error: expected a ";"
/usr/include/c++/7/bits/move.h(46): error: identifier "constexpr" is undefined
/usr/include/c++/7/bits/move.h(46): error: "_Tp" is not a function or static data member
/usr/include/c++/7/bits/move.h(51): error: expected a ";"
/usr/include/c++/7/type_traits(71): error: identifier "constexpr" is undefined
/usr/include/c++/7/type_traits(71): error: template parameter "_Tp" may not be redeclared in this scope
/usr/include/c++/7/type_traits(71): error: expected a ";"
/usr/include/c++/7/type_traits(72): error: member "__cxxabiv1::std::integral_constant<_Tp, __v>::_Tp" is not a type name
/usr/include/c++/7/type_traits(73): error: member "__cxxabiv1::std::integral_constant<_Tp, __v>::_Tp" is not a type name
/usr/include/c++/7/type_traits(74): error: identifier "constexpr" is undefined
/usr/include/c++/7/type_traits(74): error: expected a ";"
/usr/include/c++/7/type_traits(84): error: identifier "constexpr" is undefined
/usr/include/c++/7/type_traits(84): error: "_Tp" is not a function or static data member
/usr/include/c++/7/type_traits(93): error: expected a declaration
/usr/include/c++/7/type_traits(93): error: expected a ";"
/usr/include/c++/7/type_traits(126): error: space required between adjacent ">" delimiters of nested template argument lists (">>" is the right shift operator)
/usr/include/c++/7/type_traits(154): error: __bool_constant is not a template
/usr/include/c++/7/type_traits(154): error: not a class or struct name
/usr/include/c++/7/type_traits(245): error: identifier "char16_t" is undefined
/usr/include/c++/7/type_traits(249): error: identifier "char32_t" is undefined
/usr/include/c++/7/type_traits(249): error: class "__cxxabiv1::std::__is_integral_helper<<error-type>>" has already been defined
/usr/include/c++/7/type_traits(362): error: namespace "__cxxabiv1::std" has no member "size_t"
/usr/include/c++/7/type_traits(463): error: expected a ">"
/usr/include/c++/7/type_traits(467): error: expected a ">"
/usr/include/c++/7/type_traits(475): error: expected a ">"
/usr/include/c++/7/type_traits(479): error: expected a ">"
/usr/include/c++/7/type_traits(487): error: expected a ">"
/usr/include/c++/7/type_traits(491): error: expected a ">"
/usr/include/c++/7/type_traits(499): error: expected a ">"
/usr/include/c++/7/type_traits(503): error: expected a ">"
/usr/include/c++/7/type_traits(511): error: expected a ">"
/usr/include/c++/7/type_traits(515): error: expected a ">"
/usr/include/c++/7/type_traits(523): error: expected a ">"
/usr/include/c++/7/type_traits(527): error: expected a ">"
/usr/include/c++/7/type_traits(535): error: expected a ">"
/usr/include/c++/7/type_traits(539): error: expected a ">"
/usr/include/c++/7/type_traits(547): error: expected a ">"
/usr/include/c++/7/type_traits(551): error: expected a ">"
/usr/include/c++/7/type_traits(561): error: namespace "__cxxabiv1::std" has no member "nullptr_t"
/usr/include/c++/7/type_traits(582): error: space required between adjacent ">" delimiters of nested template argument lists (">>" is the right shift operator)
/usr/include/c++/7/type_traits(588): error: space required between adjacent ">" delimiters of nested template argument lists (">>" is the right shift operator)
/usr/include/c++/7/type_traits(595): error: space required between adjacent ">" delimiters of nested template argument lists (">>" is the right shift operator)
/usr/include/c++/7/type_traits(602): error: space required between adjacent ">" delimiters of nested template argument lists (">>" is the right shift operator)
/usr/include/c++/7/type_traits(612): error: space required between adjacent ">" delimiters of nested template argument lists (">>" is the right shift operator)
/usr/include/c++/7/type_traits(638): error: space required between adjacent ">" delimiters of nested template argument lists (">>" is the right shift operator)
/usr/include/c++/7/type_traits(748): error: space required between adjacent ">" delimiters of nested template argument lists (">>" is the right shift operator)
/usr/include/c++/7/type_traits(762): error: expected a ";"
/usr/include/c++/7/type_traits(777): error: space required between adjacent ">" delimiters of nested template argument lists (">>" is the right shift operator)
/usr/include/c++/7/type_traits(787): error: expected a ")"
/usr/include/c++/7/type_traits(798): error: an explicit template argument list is not allowed on this declaration
/usr/include/c++/7/type_traits(798): error: expected a type specifier
/usr/include/c++/7/type_traits(798): error: function returning function is not allowed
/usr/include/c++/7/type_traits(798): error: expected a ";"
/usr/include/c++/7/type_traits(804): error: space required between adjacent ">" delimiters of nested template argument lists (">>" is the right shift operator)
Error limit reached.
100 errors detected in the compilation of "/tmp/pgnvdP3Tc7ZGSTVCf.ii".
Compilation terminated.
PGCC-F-0155-Compiler failed to translate accelerator region (see -Minfo messages): Device compiler exited with error status code (openacc-test.cpp: 1)
PGCC/x86 Linux 18.10-1: compilation aborted
pgc++-Fatal-cpp2 completed with exit code 1
Unlinking /tmp/pgc++-YTc9tfiZkMv.il
Unlinking /tmp/pgc++3YTcLZpe7Hgh.s
Unlinking /tmp/pgc++VYTcnqU9SlJ_.ll
The undefined references are actually from the host code. The problem being that you're missing brackets around your parallel region so your only offloading the line, i.e. "seed = 12345UL".
To fix:
void do_stuff_on_gpu(){
unsigned long long seed;
unsigned long long seq;
unsigned long long offset;
curandState_t state;
#pragma acc parallel deviceptr(d_data) private(state)
{ // << Add here
seed = 12345ULL;
seq = 0ULL;
offset = 0ULL;
curand_init(seed, seq, offset, &state);
#pragma acc loop seq
for(int i = 0; i < SIZE; ++i){
d_data[i] = curand_uniform(&state);
}
} // << Add here
}
% pgc++ -fast -ta=tesla:nollvm --c++11 test.cpp -Minfo=accel
do_stuff_on_gpu():
29, Generating Tesla code
36, #pragma acc loop seq
29, CUDA shared memory used for state
The second error is actually unrelated to the first and will require a bit of detail to explain.
PGI has two back-end device code generation paths, LLVM and CUDA (nollvm), with the default being LLVM. When calling cuRAND from device code is one of the few cases when the CUDA back-end is required since the curand device code is contained in a CUDA header file that needs to get inlined. Unfortunately we don't have a way to do this yet from the LLVM path.
In general, when you see something like the second error it's due to compiling C++14 (or C++11/17) code without the appropriate language flag. The problem here is that the PGI driver isn't passing correct the language flag to the CUDA back-end compiler (cicc). It worked for me since I have GNU 4.8.5 installed so C++11 isn't on by default. However you're using GNU 7 in which C++14 is enabled, but since we're not passing "--c++14" to cicc, you get the error.
I've filled a problem report (TPR#26979) to track this issue and have asked our engineers to pass the appropriate language flag when using newer GNU versions.
As a work-around, we can update one of PGI's configuration files (pgnvdrc) so you can pass the correct flag via an environment variable. In your PGI installation, find the file "$PGI/linux86-64/18.10/bin/pgnvdrc" and make the following two line change:
% diff -u pgnvdrc.org pgnvdrc
--- pgnvdrc.org 2019-03-14 13:12:45.232168580 -0700
+++ pgnvdrc 2019-03-14 13:12:57.026220144 -0700
## -18,6 +18,8 ##
variable LDLIB is environment(LD_LIBRARY_PATH);
variable NEWLDLIB is default($LDLIB);
+variable CICCFLAG is environment(CICCFLAG);
+
variable DYLDLIB is environment(DYLD_LIBRARY_PATH);
variable NEWDYLDLIB is default($DYLDLIB);
## -547,6 +549,7 ##
set(out3=$if($CUPTXFILE,$CUPTXFILE,$if($KEEPTEMP,$basename($input).ptx,$tempfile(ptx))))
arguments(
-arch $COMPCAP -m$CUWIDTH -ftz=$FTZ -prec_div=$NOFASTMATH -prec_sqrt=$NOFASTMATH -fmad=$USEFMA
+ $CICCFLAG
$if($RELOC,--device-c)
$NVVMARGS -O$CUOPT $input -o $out3
$ifn($index($CUDAVERSION,7.5,8.0),-w)
Next set the environment variable "CICCFLAG=--c++14" and recompile.
Here I've updated my 18.10 compiler to use GNU 7.2. I can recreate the error, but after setting CICCFLAG, the code compiles correctly.
% pgc++ -fast -ta=tesla:nollvm --c++14 openacc-test.cpp
/home/sw/thirdparty/gcc/gcc-7.2.0/linux86-64/lib/gcc/x86_64-pc-linux-gnu/7.2.0/include/stddef.h(444): error: identifier "nullptr" is undefined
/home/sw/thirdparty/gcc/gcc-7.2.0/linux86-64/lib/gcc/x86_64-pc-linux-gnu/7.2.0/include/stddef.h(444): error: expected a ";"
/home/sw/thirdparty/gcc/gcc-7.2.0/linux86-64/include/c++/7.2.0/x86_64-pc-linux-gnu/bits/c++config.h(235): error: expected a ";"
... more errors ...
% setenv CICCFLAG "--c++14"
% pgc++ -fast -ta=tesla:nollvm --c++14 -Minfo=accel openacc-test.cpp
do_stuff_on_gpu():
30, Accelerator kernel generated
Generating Tesla code
36, #pragma acc loop seq
30, CUDA shared memory used for state
% a.out
Host: [data: 42.00000; data: 42.00000; data: 42.00000; data: 42.00000; data: 42.00000; data: 42.00000; data: 42.00000; data: 42.00000; data: 42.00000; data: 42.00000; data: 42.00000; data: 42.00000; data: 42.00000; data: 42.00000; data: 42.00000; data: 42.00000; ]
Host: [data: 42.00000; data: 42.00000; data: 42.00000; data: 42.00000; data: 42.00000; data: 42.00000; data: 42.00000; data: 42.00000; data: 42.00000; data: 42.00000; data: 42.00000; data: 42.00000; data: 42.00000; data: 42.00000; data: 42.00000; data: 42.00000; ]
Host: [data: 0.29890; data: 0.38100; data: 0.28855; data: 0.40197; data: 0.74258; data: 0.26742; data: 0.35657; data: 0.70735; data: 0.55123; data: 0.72577; data: 0.64131; data: 0.48502; data: 0.09711; data: 0.14655; data: 0.15180; data: 0.35960; ]
I am trying to read the name of my input file that is argv[1] . This is what I’ve done so far :
val args = CommandLine.arguments() ;
val (x::y) = args ;
val _ = agora x
but I keep getting this error message :
uncaught exception Bind [nonexhaustive binding failure] .
Can anyone help ? Thank you in advance !
This is the compiler warning you that you can't be sure that the bind pattern always holds.
For example, given the following program:
val args = CommandLine.arguments ()
val (x::y) = args
val _ = print (x ^ "\n")
Compiling and running this gives:
$ mosmlc args.sml
$ ./a.out Hello
Hello
$ ./a.out
Uncaught exception:
Bind
To safely handle a variable amount of command-line arguments, you might use a case-of:
fun main () =
case CommandLine.arguments () of
[] => print ("Too few arguments!\n")
| [arg1] => print ("That's right! " ^ arg1 ^ "\n")
| args => print ("Too many arguments!\n")
val _ = main ()
Compiling and running this gives:
$ mosmlc args2.sml
$ ./a.out
Too few arguments!
$ ./a.out hello
That's right! hello
$ ./a.out hello world
Too many arguments!
A side note: The equivalent of C's argv[0] is CommandLine.name ().
(I've spent quite some time getting this to work, so I thought I'd document it - first, to put it formally as a question):
Is there a simple example of systemtap probing/tracing functions in a user-space application, preferably in C++? My system is Ubuntu 14.04:
$ uname -a
Linux mypc 4.2.0-42-generic #49~14.04.1-Ubuntu SMP Wed Jun 29 20:22:11 UTC 2016 x86_64 x86_64 x86_64 GNU/Linux
$ g++ --version
g++ (Ubuntu 4.8.4-2ubuntu1~14.04.3) 4.8.4 ...
$ stap --version
Systemtap translator/driver (version 2.3/0.158, Debian version 2.3-1ubuntu1.4 (trusty))
OK, so this didn't turn out to be trivial - first of all, I somehow ended up with a (newer) kernel 4.2.0 on Ubuntu 14.04; and apparently the systemtap that comes with Ubuntu 14.04 is too old for that kernel (see below). That means that I had to build systemtap from source - this was my procedure:
cd /path/to/src
git clone git://sourceware.org/git/elfutils.git elfutils_git
git clone git://sourceware.org/git/systemtap.git systemtap_git
cd systemtap_git
./configure --with-elfutils=/path/to/src/elfutils_git --prefix=/path/to/src/systemtap_git/local --enable-docs=no
make
make install
# after this, there are `stap` executables in:
# /path/to/src/systemtap_git/stap
# /path/to/src/systemtap_git/local/bin/stap
This is the thing:
you shouldn't build elfutils separately, and then systemtap - you should instead pass the elfutils source directory to --with-elfutils of systemtap's configure, which will then configure and build elfutils as well.
you MUST do make install of systemtap, even if it is in a non-system/private (local) directory! - otherwise, some errors occur (unfortunately, didn't log them)
After building, stap reports version:
$ ./stap --version
Systemtap translator/driver (version 3.2/0.170, commit release-3.1-331-g0efba6fc74c8 + changes) ...
Ok, so I found a basic Fibonacci C++ example for analysis, which I slightly modified, and called /tmp/fibo.cpp:
// based on: http://www.cplusplus.com/articles/LT75fSEw/
#include <iostream>
using namespace std;
class Fibonacci{
public:
int a, b, c;
void generate(int);
void doFibonacciStep(int);
};
void Fibonacci::doFibonacciStep(int istep){
c = a + b;
cout << " istep: " << istep << " c: " << c << endl;
a = b;
b = c;
}
void Fibonacci::generate(int n){
a = 0; b = 1;
cout << " Start: a "<< a << " b " << b << endl;
for(int i=1; i<= n-2; i++){
doFibonacciStep(i);
}
}
int main()
{
cout << "Hello world! Fibonacci series" << endl;
cout << "Enter number of items you need in the series: ";
int n;
cin >> n;
Fibonacci fibonacci;
fibonacci.generate(n);
return 0;
}
First I tried compiling it like this:
cd /tmp
g++ -g fibo.cpp -o fibo.exe
Now, the first thing that we want to do, is to figure out which functions are available for probing in our executable; for that, we can use stap -L (note, here I'm still using the old, Ubuntu 14.04 system stap):
$ stap -L 'process("/tmp/fibo.exe").function("*").call'
process("/tmp/fibo.exe").function("_GLOBAL__sub_I__ZN9Fibonacci15doFibonacciStepEi").call
process("/tmp/fibo.exe").function("__static_initialization_and_destruction_0").call $__initialize_p:int $__priority:int
process("/tmp/fibo.exe").function("doFibonacciStep#/tmp/fibo.cpp:13").call $this:class Fibonacci* const $istep:int
process("/tmp/fibo.exe").function("generate#/tmp/fibo.cpp:20").call $this:class Fibonacci* const $n:int
process("/tmp/fibo.exe").function("main#/tmp/fibo.cpp:28").call
Nice - so I'd like to probe/trace the doFibonacciStep and its input argument, istep. So I try from the command line:
$ sudo stap -e 'probe process("/tmp/fibo.exe").function("Fibonacci::doFibonacciStep").call { printf("stap do step: %d\n", $istep) }' -c /tmp/fibo.exe
WARNING: "__tracepoint_sched_process_fork" [/tmp/stap51A5tV/stap_ab5b824c79b38b5207910696c49c4e22_1760.ko] undefined!
WARNING: "__tracepoint_sys_exit" [/tmp/stap51A5tV/stap_ab5b824c79b38b5207910696c49c4e22_1760.ko] undefined!
WARNING: "__tracepoint_sys_enter" [/tmp/stap51A5tV/stap_ab5b824c79b38b5207910696c49c4e22_1760.ko] undefined!
WARNING: "__tracepoint_sched_process_exec" [/tmp/stap51A5tV/stap_ab5b824c79b38b5207910696c49c4e22_1760.ko] undefined!
WARNING: "__tracepoint_sched_process_exit" [/tmp/stap51A5tV/stap_ab5b824c79b38b5207910696c49c4e22_1760.ko] undefined!
ERROR: Couldn't insert module '/tmp/stap51A5tV/stap_ab5b824c79b38b5207910696c49c4e22_1760.ko': Unknown symbol in module
WARNING: /usr/bin/staprun exited with status: 1
Pass 5: run failed. [man error::pass5]
Tip: /usr/share/doc/systemtap/README.Debian should help you get started.
$ sudo stap -e 'probe process("/tmp/fibo.exe").function("Fibonacci::doFibonacciStep").call { printf("stap do step: %d\n", $istep) }' -c /tmp/fibo.exe
ERROR: Couldn't insert module '/tmp/stapmo60OW/stap_ab5b824c79b38b5207910696c49c4e22_1760.ko': Unknown symbol in module
WARNING: /usr/bin/staprun exited with status: 1
Pass 5: run failed. [man error::pass5]
Ouch, errors like these - not good. The post "__tracepoint_sched_process_fork undefined" when run systemstap script explains that basically the stap version is too old for the kernel that I have - which required the building from source (above). So let's see now how the new stap -L works:
$ /path/to/src/systemtap_git/stap -L 'process("/tmp/fibo.exe").function("*").call'
process("/tmp/fibo.exe").function("_GLOBAL__sub_I__ZN9Fibonacci15doFibonacciStepEi#/tmp/fibo.cpp:37").call
process("/tmp/fibo.exe").function("__do_global_dtors_aux").call
process("/tmp/fibo.exe").function("__libc_csu_fini").call
process("/tmp/fibo.exe").function("__libc_csu_init").call
process("/tmp/fibo.exe").function("__static_initialization_and_destruction_0#/tmp/fibo.cpp:37").call $__initialize_p:int $__priority:int
process("/tmp/fibo.exe").function("_fini").call
process("/tmp/fibo.exe").function("_init").call
process("/tmp/fibo.exe").function("_start").call
process("/tmp/fibo.exe").function("deregister_tm_clones").call
process("/tmp/fibo.exe").function("doFibonacciStep#/tmp/fibo.cpp:13").call $this:class Fibonacci* const $istep:int
process("/tmp/fibo.exe").function("frame_dummy").call
process("/tmp/fibo.exe").function("generate#/tmp/fibo.cpp:20").call $this:class Fibonacci* const $n:int
process("/tmp/fibo.exe").function("main#/tmp/fibo.cpp:28").call
process("/tmp/fibo.exe").function("register_tm_clones").call
Nice, this is already a bit more verbose than the old version. Anyways, I'd like to probe the doFibonacciStep function, and its input argument, here $istep. So I write this on the command line:
$ sudo /path/to/src/systemtap_git/stap -e 'probe process("/tmp/fibo.exe").function("Fibonacci::doFibonacciStep").call { printf("stap do step: %d\n", $istep) }' -c /tmp/fibo.exe
semantic error: while processing probe process("/tmp/fibo.exe").function("Fibonacci::doFibonacciStep#/tmp/fibo.cpp:13").call from: process("/tmp/fibo.exe").function("Fibonacci::doFibonacciStep").call
semantic error: No cfa_ops supplied, but needed by DW_OP_call_frame_cfa: identifier '$istep' at <input>:1:107
source: probe process("/tmp/fibo.exe").function("Fibonacci::doFibonacciStep").call { printf("stap do step: %d\n", $istep) }
Pass 2: analysis failed. [man error::pass2]
Ouch - a nasty error, and doesn't really tell me anything - there are very few bug reports on this error (and mostly from 2010). So I was about to get stuck here, when for some reason, I remembered that the other day, I compiled some programs with -gdwarf-2 (for reasons I've forgotten by now); so I thought I'd try it - and whaddayaknow, it actually started working now:
$ g++ -gdwarf-2 fibo.cpp -o fibo.exe
$ sudo /path/to/src/systemtap_git/stap -e 'probe process("/tmp/fibo.exe").function("Fibonacci::doFibonacciStep").call { printf("stap do step: %d\n", $istep) }' -c /tmp/fibo.exe
Hello world! Fibonacci series
Enter number of items you need in the series: 5
Start: a 0 b 1
istep: 1 c: 1
istep: 2 c: 2
istep: 3 c: 3
stap do step: 1
stap do step: 2
stap do step: 3
Nice! Note that the stap prints are actually printed after the program has finished (that is, they are not interleaved with the actual program output where they occured).
Instead of specifying the probe points and behavior directly on the command line, we could write a script instead - so here is check-do-step.stp - here with some extra stuff:
#!/usr/bin/env stap
global stringone = "Testing String One"
global stringtwo = "Testing String Two"
probe begin {
printf("begin: %s\n", stringone)
#exit() # must have; else probe end runs only upon Ctrl-C if we only have `begin` and `end` probes!
}
probe process(
"/tmp/fibo.exe"
).function(
"Fibonacci::doFibonacciStep"
).call {
printf("stap do step: %d\n", $istep)
}
probe end {
newstr = "We Are " . stringtwo . " And We're Done" # string concat
printf("%s\n", newstr)
}
... and with this script, our call and results look like this:
$ sudo /path/to/src/systemtap_git/stap check-do-step.stp -c /tmp/fibo.exe
Hello world! Fibonacci series
Enter number of items you need in the series: begin: Testing String One
6
Start: a 0 b 1
istep: 1 c: 1
istep: 2 c: 2
istep: 3 c: 3
istep: 4 c: 5
stap do step: 1
stap do step: 2
stap do step: 3
stap do step: 4
We Are Testing String Two And We're Done
Notice again - the begin: Testing ... string does not hit at the very start as we'd otherwise expect, but only after the program already started generating output.
Well, I guess this is it - certainly good enough for me, for a simple example...
gcov is a GNU toolchain utility that produces code coverage reports (see documentation) formated as follows:
-: 0:Source:../../../edg/attribute.c
-: 0:Graph:tmp.gcno
-: 0:Data:tmp.gcda
-: 0:Runs:1
-: 0:Programs:1
-: 1:#include <stdio.h>
-: 2:
-: 3:int main (void)
1: 4:{
1: 5: int i, total;
-: 6:
1: 7: total = 0;
-: 8:
11: 9: for (i = 0; i < 10; i++)
10: 10: total += i;
-: 11:
1: 12: if (total != 45)
#####: 13: printf ("Failure\n");
-: 14: else
1: 15: printf ("Success\n");
1: 16: return 0;
-: 17:}
I need to extract the line numbers of the lines that were executed from a bash script. $ egrep --regexp='^\s+[1-9]' example_file.c.gcov seems to return the relevant lines. An exemple of typical output would be:
1: 978: attr_name_map = alloc_hash_table(NO_MEMORY_REGION_NUMBER,
79: 982: for (k = 0; k<KNOWN_ATTR_TABLE_LENGTH; ++k) {
78: 989: attr_name_map_entries[k].descr = &known_attr_table[k];
78: 990: *ep = &attr_name_map_entries[k];
1: 992:} /* init_attr_name_map */
519: 2085: new_attr_seen = FALSE;
519: 2103: p_attributes = last_attribute_link(p_attributes);
519: 2104: } while (new_attr_seen);
519: 2106: return attributes;
16: 3026:void transform_type_with_gnu_attributes(a_type_ptr *p_type,
16: 3041: for (ap = attributes; ap != NULL; ap = ap->next) {
1: 6979:void process_alias_fixup_list(void)
1: 6984: an_alias_fixup_ptr entries = alias_fixup_list, entry;
I subsequently must extract the line number strings. The expected output from this example would be:
978
982
989
990
992
2085
2103
2104
2106
3026
3041
6979
6984
Could someone suggest a reliable, robust way to achieve this?
NOTE:
My idea was to eliminate everything that is not placed between the first and the second instance of the character :, which I tried to do with sed without much success so far.
This is fairly simple to do using awk:
awk -F: '/ +[0-9]/ {gsub(/ /, "", $2); print $2}' file.gcov
That is, use : as the field separator,
and for lines starting with spaces and digits,
replace the spaces from the 2nd field and print the 2nd field.
But if you really want to use sed,
and you want something robust, you could do this:
sed -e '/^ *[0-9][0-9]*: *[0-9][0-9]*:/!d' -e 's/[^:]*: *//' -e 's/:.*//' file.gcov
What's happening here?
The first command uses a pattern to match lines starting with 1 or more spaces followed by 1 or more digits followed by a : followed by 1 or more spaces followed by 1 or more digits followed by a :. Then comes the interesting part, we invert this selection with ! and delete it with d. We effectively delete all other lines except the ones we need.
The second command is a simple substitution, replacing a sequence of characters that are not : followed by a : followed by zero or more spaces. The pattern is applied from the beginning of the line so no need for a starting ^, and no need to specify strictly 1-or-more-spaces, thanks to the previous command we already know that there will be at least one.
The last command is even simpler, replace a : and everything after it.
Some versions of sed will give you shortcuts for a more compact writing style, for example [0-9]+ instead of [0-9][0-9]*, but the example above will work with a wider variety of implementations (notably BSD).
I start my program with
int main (int argc, char *argv[]) {
printf("%d \n", argc);
then I compiled in Ubuntu using g++, and I ran the program using
./calc 2 3 4 + *
but the program outputs 17! I did a printf on the arguments as well, they are:
arg 0: ./calc
arg 1: 2
arg 2: 3
arg 3: 4
arg 4: +
arg 5: 1.2.c
arg 6: 1.3.c
arg 7: 1.4.c
arg 8: 2.1.c
arg 9: 2.2.c
arg 10: 2.3.c
arg 11: 2.4.c
arg 12: 3.2.c
arg 13: 3.4.c
arg 14: 4.1.c
arg 15: a.out
arg 16: calc
but obviously that's not what I'm expecting. How can I correct this?
The * is being evaluated by your shell to mean all of the files in the current directory. You should escape the asterisk using \*.
The linux shell interpreted * as a listing of all the files in a directory. Try escaping it with "\" e.g.
./calc 2 3 4 + \*
or
./calc 2 3 4 + "*"