How do I FFI a CUDA application on Haskell? - haskell

I've ported a Haskell application to CUDA in order to accelerate it. Now, I have a .cu file which I want to use from Haskell as an API. I've managed to FFI C files easily following the tutorials, but I'm not sure how this applies to CUDA/nvcc. How do I do it?
For completion, this is what I get trying to treat the .cu as a normal .c file:
vh:CUDA apple1$ nvcc hello.cu -c -o hello.o
vh:CUDA apple1$ ghc test.hs -o test hello.o
Linking test ...
Undefined symbols for architecture x86_64:
"___cudaRegisterFatBinary", referenced from:
__sti____cudaRegisterAll_40_tmpxft_00002168_00000000_7_hello_cpp1_ii_f33df8d2() in hello.o
"___cudaRegisterFunction", referenced from:
__nv_cudaEntityRegisterCallback(void**) in hello.o
"___cudaUnregisterFatBinary", referenced from:
__cudaUnregisterBinaryUtil() in hello.o
"_cudaConfigureCall", referenced from:
render(Renderer_*) in hello.o
"_cudaFree", referenced from:
renderer_free(Renderer_*) in hello.o
"_cudaLaunch", referenced from:
cudaError cudaLaunch<char>(char*) in hello.o
"_cudaMalloc", referenced from:
renderer_init(Renderer_*, float, float, float, float, float) in hello.o
"_cudaMemcpy", referenced from:
renderer_init(Renderer_*, float, float, float, float, float) in hello.o
render(Renderer_*) in hello.o
"_cudaSetupArgument", referenced from:
__device_stub__Z4walk6float3PiS_S_S_S_S0_(float3&, int*, float3&, float3&, float3&, float3&, int*) in hello.o
"_hello", referenced from:
_r3yw_info in test.o
_c3Ib_info in test.o
_c3Il_info in test.o
(maybe you meant: _Main_hello_closure, _Main_hello_info )
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
And that is my Haskell file:
{-# LANGUAGE ForeignFunctionInterface #-}
module Main where
import Foreign.C
import Foreign.Ptr (Ptr,nullPtr)
foreign import ccall "hello" hello :: IO ()
main = hello

I managed to solve it by adding extern "C" to all functions on hello.cu:
-- hello.cu
extern "C"
void hello();
Compiling the CUDA file with:
nvcc -c hello.cu
And the Haskell file with:
ghc --make test.hs -o test hello.o -L/usr/local/cuda/lib -optl-lcudart

Related

How to compile HSL for IPOPT (after IPOPT)

I use MINGW64 to compile HSL (https://www.hsl.rl.ac.uk/ipopt/) following the redme. However, I end up with an error 2 (Makefile:753). The critical command is
gfortran -shared .libs/libcoinhsl-0.dll.def common/.libs/deps90.o common/.libs/deps.o common/.libs/dump.o mc19/.libs/mc19d.o ma27/.libs/ma27d.o ma28/.libs/ma28d.o ma57/.libs/ma57d.o hsl_ma77/.libs/hsl_ma77d.o hsl_ma77/C/.libs/hsl_ma77d_ciface.o hsl_ma86/.libs/hsl_ma86d.o hsl_ma86/C/.libs/hsl_ma86d_ciface.o hsl_mc68/C/.libs/hsl_mc68i_ciface.o hsl_ma97/.libs/hsl_ma97d.o hsl_ma97/C/.libs/hsl_ma97d_ciface.o loadmetis/.libs/loadmetis.o -L/mingw64/lib/ -lopenblas -lpthread -lgfortran -O2 -Wl,-rpath -Wl,/mingw64/lib -o .libs/libcoinhsl-0.dll -Wl,--enable-auto-image-base -Xlinker --out-implib -Xlinker .libs/libcoinhsl.dll.a
The output is
C:/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/10.3.0/../../../../x86_64-w64-mingw32/bin/ld.exe: common/.libs/deps90.o:C:\msys64\home\user\hsl_solo\coinhsl/common/deps90.f90:17672: undefined reference to `metis_nodend_'
C:/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/10.3.0/../../../../x86_64-w64-mingw32/bin/ld.exe: common/.libs/deps90.o: in function `__hsl_mc68_integer_MOD_mc68_order_integer':
C:\msys64\home\user\hsl_solo\coinhsl/common/deps90.f90:17454: undefined reference to `metis_nodend_'
C:/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/10.3.0/../../../../x86_64-w64-mingw32/bin/ld.exe: ma57/.libs/ma57d.o: in function `ma57ad_':
C:\msys64\home\user\hsl_solo\coinhsl/ma57/ma57d.f:469: undefined reference to `metis_nodend_'
C:/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/10.3.0/../../../../x86_64-w64-mingw32/bin/ld.exe: C:\msys64\home\user\hsl_solo\coinhsl/ma57/ma57d.f:682: undefined reference to `metis_nodend_'
C:/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/10.3.0/../../../../x86_64-w64-mingw32/bin/ld.exe: C:\msys64\home\user\hsl_solo\coinhsl/ma57/ma57d.f:618: undefined reference to `metis_nodend_'
collect2.exe: error: ld returned 1 exit status
As I am not that experienced with compiling software, does anyone have an idea how I can get this error fixed?
Symbol metis_nodend_ belongs to Metis.
The metis_nodend_ symbol needs to be resolved either by linking against a Metis library (you might need to specify where to find that via some flags for configure), by a function of that name that loads the Metis library at runtime (that is what loadmetis tries to do), or by a dummy function of that name that does nothing (thats what older versions of HSL used to do).
The loadmetis of HSL is implemented in C and defines a function METIS_NODEND:
void METIS_NODEND(int *nvtxs, int *xadj, int *adjncy, int *numflag,
int *options, int *perm, int *iperm) {
....
So the problem is probably that the naming conventions do not match, i.e., the functionname in the C object does not match the functionname that the Fortran objects expect.
Try changing METIS_NODEND to metis_nodend or metis_nodend_ in loadmetis.c.
Or try the buildsystem from https://github.com/coin-or-tools/ThirdParty-HSL/

Why linkage failed even when nm found the symbol?

When I compile a demo main.cpp, it failed because undefined reference to a_mtk_bt_service_init(), but I have found the symbol by
nm -D ./libmtk_bt_service_client.so|grep a_mtk_bt_service_init,
it's output is 0000000000004098 T a_mtk_bt_service_init,
I'm sure the compiler found the correct dynamic library by use command aarch64-poky-linux-g++ -print-file-name=libmtk_bt_service_client.so -o main main.cpp
This is the demo code main.cpp
void a_mtk_bt_service_init();
int main()
{
a_mtk_bt_service_init();
return 0;
}
and my compile command is
aarch64-poky-linux-g++ -mcpu=cortex-a72.cortex-a53+crypto -mtune=cortex-a72.cortex-a53 --sysroot=/home/sundq/code/newT9/T9-Amazon-Sdk/build/tmp/sysroots/aud8516-slc -o build/xx main.cpp -I../../include -lmtk_bt_service_client
The answer is here Call a C function from C++ code, that is, when c++ code call a c function, we also must add extern "C" before the declare of c function,
so my function declare should like this
extern "C" void a_mtk_bt_service_init();

why linking to a static library is generally faster than linking to individual source files?

case 1. gcc -o program main.o file1.o file2.o
case 2. ar crv foo.a file1.o file2.o
then, gcc -o program main.o foo.a
At compile time, linking to a static library (case 2) is generally faster than linking to individual source files.(case 1)
Why and what cases?
Any help is appreciated.
/* Filename :lib.h */
void file2(char *);
void file1(int);
main.c
#include "lib.h"
int main()
{
file1(3);
file2("Hello World");
return 0;
}
file1.c
#include <stdio.h>
#include "lib.h"
void file1(int arg) {
printf("you passed %d\n", arg);
} 
file2.c
#include <stdio.h>
#include "lib.h"
void file2(char* arg) {
printf("you passed %s\n", arg);
}
The only case I can think of is when your object files are rather large.
Linking against a library will only "pull in" referenced items. So your executable can be smaller and the functions closer in memory for shorter jumps. But that is an unlikely thing in a modern platform.

GHC: how to build a 32-bit DLL using 64-bit GHC? (To call functions from c++)

I'd like to build the 32-bit DLL with 64-bit GHC. And here is the minimal example.
Test.hs
{-# LANGUAGE ForeignFunctionInterface #-}
module Test where
import Foreign.C.Types
foreign export ccall c_hello :: IO()
foreign export ccall boo :: CInt
c_hello :: IO()
c_hello = do
print "Hello!"
init_exit.cpp
#include "Test_stub.h"
#include <C:\Program Files\Haskell Platform\8.0.1\lib\include\Rts.h>
#define DLLExport extern "C" __declspec(dllexport)
DLLExport void hello()
{
c_hello();
}
DLLExport int HsStart()
{
int argc = 1;
char* argv[] = {"ghcDLL", NULL};
char** args = argv;
hs_init(&argc, &args);
printf("Haskell library has been initialized!\n");
return 0;
}
DLLExport int HsEnd()
{
hs_exit();
printf("Haskell library has been finalized!\n");
return 0;
}
And then I build the library, using the following commands:
ghc -c -O Test.hs
ghc -c init_exit.cpp
ghc -shared -o Test.dll Test.o init_exit.o
What flags should I pass to ghc or maybe to gcc to build the 32-bit DLL instead of 64-bit? Or maybe there is another way to do this.
A normal Windows 64-bit GHC build (such as the one you can download from the GHC website) is only capable of building 64-bit object files. For example, it doesn't include 32-bit versions of any of the libraries that come with GHC.
Your options are to build a Windows 64-bit to Windows 32-bit cross-compiler, or just run the normal Windows 32-bit build of GHC (probably much easier).

How to place `library (RgoogleMaps)` inside the code of Rcpp?

#include "rtest.h"
#include <iostream>
SEXP rcpp_hello_world ()
{
using namespace Rcpp ;
CharacterVector x = CharacterVector::create( "foo", "bar" );
NumericVector y = NumericVector::create( 0.0, 1.0 );
List z = List::create (x, y);
return z;
}
void funcA ()
{
std :: cout << "\nsdfsdfsdf\n";
}
int main () {return 0;}
How to place
library(RgoogleMaps)
and
png (filename="Rg.png", width=480, height=480)
inside the above code?
I run it as: R CMD SHLIB rtest.cpp
> sessionInfo()
R version 2.15.1 (2012-06-22)
Platform: x86_64-unknown-linux-gnu (64-bit)
locale:
[1] LC_CTYPE=en_US.UTF-8 LC_NUMERIC=C
[3] LC_TIME=en_US.UTF-8 LC_COLLATE=en_US.UTF-8
[5] LC_MONETARY=en_US.UTF-8 LC_MESSAGES=en_US.UTF-8
[7] LC_PAPER=C LC_NAME=C
[9] LC_ADDRESS=C LC_TELEPHONE=C
[11] LC_MEASUREMENT=en_US.UTF-8 LC_IDENTIFICATION=C
attached base packages:
[1] stats graphics grDevices utils datasets methods base
>
Rcpp's version is 0.9.13
I tried:
R CMD SHLIB -lRgoogleMaps rtest.cpp
It resulted in:
anisha#linux-y3pi:~/> R CMD SHLIB -lRgoogleMaps rtest.cpp
g++ -I/usr/lib64/R/include -DNDEBUG -I/usr/local/include -I/usr/lib64/R/library/Rcpp/include -fpic -fmessage-length=0 -O2 -Wall -D_FORTIFY_SOURCE=2 -fstack-protector -funwind-tables -fasynchronous-unwind-tables -c rtest.cpp -o rtest.o
g++ -shared -L/usr/local/lib64 -o rtest.so rtest.o -lRgoogleMaps -L/usr/lib64/R/lib -lR
/usr/lib64/gcc/x86_64-suse-linux/4.5/../../../../x86_64-suse-linux/bin/ld: cannot find -lRgoogleMaps
collect2: ld returned 1 exit status
make: *** [rtest.so] Error 1
I think you have a bit of a conceptual problem here between what
library(RgoogleMaps)
does in R, and what a library is for a compiler
-lfoo -Lpath/to/library
The two are not the same, despite the fact that we use the English noun "library" in both cases.
You may need to brush up a little with a text on programming, compilers, linkers, ...
Why would you want to do this? Rcpp is designed for interfacing C++ code within an R session so that you can exploit faster computation or re-use existing C++ libraries.
Write an R wrapper that calls the Rcpp code, have that wrapper arrange for the package to be made available (using require(RgoogleMaps)).
Second, you don't want to hard code the plotting device. Again, you could do this in R:
png(filename="Rg.png", width=480, height=480)
##
## call Rcpp function
## in here
dev.off()
Rcpp isn't meant for writing standalone C++ applications, you still want to interact with it from an R session.

Resources