Skip to content

Commit

Permalink
Try building CUDA
Browse files Browse the repository at this point in the history
  • Loading branch information
imciner2 committed Dec 5, 2023
1 parent 0ca11f6 commit 2e2f933
Show file tree
Hide file tree
Showing 3 changed files with 148 additions and 23 deletions.
122 changes: 111 additions & 11 deletions @osqp/build.m
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ function build(varargin)
% empty: Build osqp_mex interface
% 'all': Build all interfaces
% 'osqp_mex': Builds the OSQP mex interface
% 'osqp_cuda': Builds the OSQP mex interface with the CUDA backend
% 'clean': Delete all compiled files
% 'purge': Delete all compiled files and copied code generation files
%
Expand All @@ -15,26 +16,24 @@ function build(varargin)

p = inputParser;

addOptional( p, 'target', 'osqp_mex' );
addOptional( p, 'verbose', false );
targets = {'all', 'osqp_mex', 'osqp_cuda', 'clean', 'purge'};

addOptional( p, 'target', 'osqp_mex', @(s) length( validatestring(s, targets) > 0 ) );
addParameter( p, 'verbose', false );
addParameter( p, 'toolchain', 'default', @isstring )

parse( p, varargin{:} );

target = p.Results.target;
verbose = p.Results.verbose;

if(isempty(strfind(target, 'all')) && ...
isempty(strfind(target, 'osqp_mex')) && ...
isempty(strfind(target, 'clean')) && ...
isempty(strfind(target, 'purge')))
fprintf('No rule to make target "%s", exiting.\n', target);
end
cuda_toolchain = p.Results.toolchain;

%% Determine where the various files are all located
% Various parts of the build system
[osqp_classpath,~,~] = fileparts( mfilename( 'fullpath' ) );
osqp_mex_src_dir = fullfile( osqp_classpath, '..', 'c_sources' );
osqp_mex_build_dir = fullfile( osqp_mex_src_dir, 'build' );
osqp_mex_cuda_build_dir = fullfile( osqp_mex_src_dir, 'build_cuda' );
osqp_cg_src_dir = fullfile( osqp_mex_build_dir, 'codegen_src' );
osqp_cg_dest_dir = fullfile( osqp_classpath, '..', 'codegen', 'sources' );

Expand Down Expand Up @@ -125,9 +124,108 @@ function build(varargin)
fprintf( '\t\t\t\t\t\t[done]\n' );
end

%% Configure, build and install the OSQP CUDA mex interface
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
if( any(strcmpi(target, 'osqp_cuda')) || any(strcmpi(target, 'all')) )
fprintf('Compiling OSQP CUDA solver mex interface...\n');

% Create build for the mex file and go inside
if exist( osqp_mex_cuda_build_dir, 'dir' )
rmdir( osqp_mex_cuda_build_dir, 's' );
end
mkdir( osqp_mex_cuda_build_dir );

% Extend path for CMake mac (via Homebrew)
PATH = getenv('PATH');
if( (ismac) && (isempty(strfind(PATH, '/usr/local/bin'))) )
setenv('PATH', [PATH ':/usr/local/bin']);
end

%% Figure out the CUDA toolkit and compiler location
if( any(strcmpi(cuda_toolchain, 'default')) || any(strcmpi(target, 'builtin')) )

if( exist('mexcuda') )
cmd = "mexcuda -n -v NVCCFLAGS='$NVCCFLAGS -allow-unsupported-compiler' " + osqp_mex_src_dir + filesep + "configure" + filesep + "config.cu";
x = evalc( cmd );

[tok, match] = regexp(x, 'CUDA_ROOT : ([^\n])*', 'tokens', 'match');
cuda_root = tok{1}{1};

[tok, match] = regexp(x, 'CUDA_LIBS : ([^\n])*', 'tokens', 'match');
cuda_libs = tok{1}{1};

if( verbose )
fprintf( ' Found CUDA_ROOT=%s\n', cuda_root );
fprintf( ' Found CUDA_LIBS=%s\n', cuda_libs );
end
elseif( strcmpi(target, 'builtin') )
error( 'Unable to locate the builtin MATLAB CUDA toolchain' );
elseif( verbose )
fprintf( ' Using CMake CUDA toolchain detection\n' );
end
else
cuda_root = cuda_toolchain;

if( verbose )
fprintf( '\n' );
fprintf( ' Using CUDA_ROOT=%s\n', cuda_root );
end
end

%% Configure CMake for the mex interface
fprintf(' Configuring...' )
[status, output] = system( sprintf( 'cmake -B %s -S %s -DCMAKE_BUILD_TYPE=RelWithDebInfo -DMATLAB_CUDA=ON -DMATLAB_CUDA_ROOT=\"%s\" -DMATLAB_CUDA_LIBS=\"%s\" -DMatlab_ROOT_DIR=\"%s\"', ...
osqp_mex_cuda_build_dir, ...
osqp_mex_src_dir, ...
cuda_root, ...
cuda_libs, ...
Matlab_ROOT ), 'LD_LIBRARY_PATH', '' );
if( status )
fprintf( '\n' );
disp( output );
error( 'Error configuring CMake environment' );
elseif( verbose )
fprintf( '\n' );
disp( output );
else
fprintf( '\t\t\t\t\t[done]\n' );
end

%% Build the mex interface
fprintf( ' Building...')
[status, output] = system( sprintf( 'cmake --build %s --config Release', osqp_mex_cuda_build_dir ), 'LD_LIBRARY_PATH', '' );
if( status )
fprintf( '\n' );
disp( output );
error( 'Error compiling OSQP mex interface' );
elseif( verbose )
fprintf( '\n' );
disp( output );
else
fprintf( '\t\t\t\t\t\t[done]\n' );
end

%% Install various files
fprintf( ' Installing...' )

% Copy mex file to root directory for use
if( ispc )
[err, errmsg, ~] = copyfile( [osqp_mex_cuda_build_dir, filesep, 'Release', filesep, 'osqp_mex.mex*'], [osqp_classpath, filesep, 'private'] );
else
[err, errmsg, ~] = copyfile( [osqp_mex_cuda_build_dir, filesep, 'osqp_mex.mex*'], [osqp_classpath, filesep, 'private'] );
end
if( ~err )
fprintf( '\n' )
disp( errmsg )
error( ' Error copying mex file' )
end

fprintf( '\t\t\t\t\t\t[done]\n' );
end

%% Clean and purge
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
if( any(strcmpi(target, 'clean')) || any(strcmpi(wtargethat, 'purge')) )
if( any(strcmpi(target, 'clean')) || any(strcmpi(target, 'purge')) )
fprintf('Cleaning OSQP mex files and build directory...');

% Delete mex file
Expand All @@ -140,7 +238,9 @@ function build(varargin)
if exist(osqp_mex_build_dir, 'dir')
rmdir(osqp_mex_build_dir, 's');
end

if exist(osqp_mex_cuda_build_dir, 'dir')
rmdir(osqp_mex_cuda_build_dir, 's');
end

fprintf('\t\t[done]\n');

Expand Down
48 changes: 36 additions & 12 deletions c_sources/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -14,34 +14,51 @@ include_directories( ${Matlab_INCLUDE_DIRS} )
set( CMAKE_CXX_STANDARD 11 )
set( CMAKE_CXX_STANDARD_REQUIRED ON )

# Some options
option( MATLAB_CUDA "Build CUDA backend" OFF )

if( CMAKE_COMPILER_IS_GNUCXX )
# Add debug symbols and optimizations to the build
set( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g -O2" )
set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -O2" )
endif()

# Insist on the pre-2018 complex data API so that mxGetPr will work correctly
add_compile_definitions( MATLAB_MEXSRC_RELEASE=R2017b )
add_compile_definitions( MATLAB_MEXSRC_RELEASE=R2017b )
message( STATUS "Using Matlab pre-2018a API for mxGetPr compatibility" )

# Some parts of the main libraries need to know we are building for MATLAB
# So pass a definition to let them know
add_compile_definitions( MATLAB )

# Configure the settings of the OSQP library
set( OSQP_ALGEBRA_BACKEND "builtin" )
set( OSQP_USE_FLOAT OFF )
set( OSQP_CODEGEN ON )
set( OSQP_ENABLE_DERIVATIVES ON )
set( OSQP_ENABLE_PRINTING ON )
set( OSQP_ENABLE_PROFILING ON )
set( OSQP_ENABLE_INTERRUPT ON )
if( MATLAB_CUDA )
message( STATUS "Building CUDA-based mex file" )
set( OSQP_ALGEBRA_BACKEND "cuda" CACHE STRING "Build CUDA mex file" )
set( OSQP_CODEGEN OFF CACHE BOOL "Disable codegen" )
set( OSQP_ENABLE_DERIVATIVES OFF CACHE BOOL "Disable derivatives" )

# Give CMake hints for where to find libraries
set( CUDAToolkit_ROOT "${MATLAB_CUDA_ROOT}" CACHE STRING "CUDA Toolkit root directory" )
set( CUDA_TOOLKIT_ROOT_DIR "${MATLAB_CUDA_ROOT}" CACHE STRING "CUDA Toolkit root directory" )
set( CUDA_HOME "${MATLAB_CUDA_ROOT}" CACHE STRING "CUDA Toolkit root directory" )
else()
message( STATUS "Building builtin algebramex file")
set( OSQP_ALGEBRA_BACKEND "builtin" CACHE STRING "Build builtin algebra")
set( OSQP_CODEGEN ON CACHE BOOL "Enable codegen" )
set( OSQP_ENABLE_DERIVATIVES ON CACHE BOOL "Enable derivatives" )
endif()

set( OSQP_USE_FLOAT OFF CACHE BOOL "Use doubles" )
set( OSQP_ENABLE_PRINTING ON CACHE BOOL "Enable printing" )
set( OSQP_ENABLE_PROFILING ON CACHE BOOL "Enable profiling" )
set( OSQP_ENABLE_INTERRUPT ON CACHE BOOL "Enable interrupt" )

# Configure the build outputs for the OSQP library
set( OSQP_BUILD_STATIC_LIB ON )
set( OSQP_BUILD_SHARED_LIB OFF )
set( OSQP_BUILD_UNITTESTS OFF )
set( OSQP_BUILD_DEMO_EXE OFF )
set( OSQP_BUILD_STATIC_LIB ON CACHE BOOL "Build static library" )
set( OSQP_BUILD_SHARED_LIB OFF CACHE BOOL "Disable shared library" )
set( OSQP_BUILD_UNITTESTS OFF CACHE BOOL "Disable unit tests" )
set( OSQP_BUILD_DEMO_EXE OFF CACHE BOOL "Disable demo executable" )

# Add the custom MATLAB memory handling
set( OSQP_CUSTOM_MEMORY "memory_matlab.h" )
Expand All @@ -63,6 +80,12 @@ else()
set( UT_LIBRARY "-L${Matlab_LIB_DIR} -lut" )
endif()

if( MATLAB_CUDA )
set( ADDITIONAL_LIBS "-L${MATLAB_CUDA_LIBS}" )
else()
set( ADDITIONAL_LIBS "")
endif()

matlab_add_mex( NAME osqp_mex
SRC ${CMAKE_CURRENT_SOURCE_DIR}/osqp_mex.cpp
${CMAKE_CURRENT_SOURCE_DIR}/interrupt_matlab.c
Expand All @@ -71,5 +94,6 @@ matlab_add_mex( NAME osqp_mex
${CMAKE_CURRENT_SOURCE_DIR}/osqp_struct_settings.cpp
LINK_TO osqpstatic
${UT_LIBRARY}
${ADDITIONAL_LIBS}
# Force compilation in the traditional C API (equivalent to the -R2017b flag)
R2017b )
1 change: 1 addition & 0 deletions c_sources/configure/config.cu
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
#include <cuda.h>

0 comments on commit 2e2f933

Please sign in to comment.