-
Notifications
You must be signed in to change notification settings - Fork 88
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
C API Support #1626
base: develop
Are you sure you want to change the base?
C API Support #1626
Conversation
…to pasc_update
Initial API support for iterative solvers with preconditioner, factorization and direct solvers
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the work, this looks already quite good! I left some remarks below.
The big points I want to bring up are:
- executor function names. I'm not sure
_cpu
,_gpu
parts are necessary for executor function names. From the rest of the name, it is already implied if it is for a cpu or gpu executor or not. Also this implies a type hierarchy level that is not really present in ginkgo at the moment. - naming consistency. Should the prefix be
ginkgo
orgko
. I might tend togko
, since that matches our namespace. - error handling. A lot of Ginkgo functions can throw, and I'm unsure what will happen on the C side in that case. I guess the standard approach would be to catch the exception and return error codes instead.
* @param _name Name of the datatype of the array | ||
* | ||
*/ | ||
#define DEFINE_ARRAY_OVERLOAD(_ctype, _cpptype, _name) \ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure the define macros should be placed in the header. They add information that is unnecessary for users, and which they should not rely on.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
True, since they are only required in c_api.cpp
, they could also be defined there.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In addition to putting them in c_api.cpp
, I would also recommend prefixing all of them with GKO_
.
\ | ||
size_t ginkgo_array_##_name##_get_size(gko_array_##_name array_st_ptr) \ | ||
{ \ | ||
return (*array_st_ptr).arr.get_size(); \ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Am I missing something or could the (*struct).member
syntax be simplified:
return (*array_st_ptr).arr.get_size(); \ | |
return array_st_ptr->arr.get_size(); \ |
void ginkgo_linop_apply(gko_linop A_st_ptr, gko_linop b_st_ptr, | ||
gko_linop x_st_ptr); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
how does this work with b
and x
as vectors? Is there a way to convert the ginkgo_matrix_dense_f32
to a gko_linop
?
* parameter | ||
* | ||
*/ | ||
struct gko_deferred_factory_parameter_st; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why does this use gko_
instead of ginkgo_
? Same for the other instances below.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was thinking to use gko_
for struct objects and ginkgo_
for actual methods, and thus I used gko_linop
, gko_deferred_factory_parameter
, gko_executor
etc.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it's more common for c libraries to have a single prefix that they stick to.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Makes sense! Probably we should opt for using just gko_
then?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That is what I would prefer.
gko_linop x_st_ptr); | ||
|
||
//-------------------- Iterative solvers ----------------------------- | ||
gko_linop ginkgo_linop_cg_preconditioned_f64_create( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think I would prefer
gko_linop ginkgo_linop_cg_preconditioned_f64_create( | |
gko_linop ginkgo_solver_cg_preconditioned_f64_create( |
since that matches again the namespace.
Also, I would leave out preconditioned
from the name, since there is no non-preconditioned version.
/* ---------------------------------------------------------------------- | ||
* C memory management | ||
* ---------------------------------------------------------------------- */ | ||
void c_char_ptr_free(char* ptr); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what is this doing here? It doesn't seem to be related to ginkgo.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was experimenting a bit around the I/O interfacing and tried to have dense matrices printed using _write_mtx
(defined under macro).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you need this as a public function, it must be prefixed (for functions, you seem to use ginkgo_
).
if (auto omp_exec = std::dynamic_pointer_cast<gko::OmpExecutor>( | ||
exec_st_ptr->shared_ptr)) { | ||
return new gko_executor_st{ | ||
gko::CudaExecutor::create(device_id, exec_st_ptr->shared_ptr)}; | ||
} else if (auto reference_exec = | ||
std::dynamic_pointer_cast<gko::ReferenceExecutor>( | ||
exec_st_ptr->shared_ptr)) { | ||
return new gko_executor_st{ | ||
gko::CudaExecutor::create(device_id, exec_st_ptr->shared_ptr)}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
could be combined
if (auto omp_exec = std::dynamic_pointer_cast<gko::OmpExecutor>( | |
exec_st_ptr->shared_ptr)) { | |
return new gko_executor_st{ | |
gko::CudaExecutor::create(device_id, exec_st_ptr->shared_ptr)}; | |
} else if (auto reference_exec = | |
std::dynamic_pointer_cast<gko::ReferenceExecutor>( | |
exec_st_ptr->shared_ptr)) { | |
return new gko_executor_st{ | |
gko::CudaExecutor::create(device_id, exec_st_ptr->shared_ptr)}; | |
if ( std::dynamic_pointer_cast<gko::OmpExecutor>( | |
exec_st_ptr->shared_ptr) || | |
std::dynamic_pointer_cast<gko::ReferenceExecutor>( | |
exec_st_ptr->shared_ptr)) { | |
return new gko_executor_st{ | |
gko::CudaExecutor::create(device_id, exec_st_ptr->shared_ptr)}; |
same for hip and sycl
} | ||
} | ||
|
||
size_t ginkgo_executor_cuda_get_num_devices() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this should return an int
instead of size_t
, since that's what the ginkgo function returns.
Or is the size_t
required from the julia side.
This also applies to many of the executor functions.
/* ---------------------------------------------------------------------- | ||
* Library functions for creating arrays and array operations in GINKGO | ||
* ---------------------------------------------------------------------- */ | ||
DECLARE_ARRAY_OVERLOAD(int16_t, int16_t, i16) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think the int16
overload is useful. It can't be used to create matrices, or basically anything relevant. Instead, a size_t
might be more helpful, although this is also not necessary for the functions currently available in the C-API.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just some quick comments
#ifndef C_API_H | ||
#define C_API_H |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
#ifndef C_API_H | |
#define C_API_H | |
#ifndef GKO_C_API_H | |
#define GKO_C_API_H |
Maybe better to prefix with GKO to avoid potential collisions.
* @param _name Name of the datatype of the array | ||
* | ||
*/ | ||
#define DEFINE_ARRAY_OVERLOAD(_ctype, _cpptype, _name) \ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
True, since they are only required in c_api.cpp
, they could also be defined there.
* its construction by removing the repetitive typing of array's name. | ||
* | ||
* @param _ctype_value Type name of the element type in C | ||
* |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
* |
We rather keep all the @param together instead of separating them by an empty line.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you! I will edit the ones that do not match the format
* construction by removing the repetitive typing of array's name. | ||
* | ||
* @param _ctype Type name of the element type in C | ||
* |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
* |
We rather keep the @param together instead of separating them by an empty line.
remove redundant author comments Co-authored-by: Gregor Olenik <gregor.olenik@web.de>
remove redundant author comments Co-authored-by: Gregor Olenik <gregor.olenik@web.de>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good work in general!
Most of my comments are about names and moving things to the CPP file.
Also, you seem to mix the prefix gko_
(mostly structs) and ginkgo_
(functions).
I don't think we need to make a distinction here,
I would recommend to use gko_
for everything (and GKO_
for macros), as you have already discussed with @MarcelKoch in the comments.
I need to read up a bit more on C APIs to give my final review, so consider this 1/2.
// | ||
// SPDX-License-Identifier: BSD-3-Clause | ||
|
||
#include <../include/ginkgo/c_api.h> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
<>
means it's in one of the header directories, so this should be:
#include <../include/ginkgo/c_api.h> | |
#include <ginkgo/c_api.h> |
Alternatively, if you want to specify the relative path, use regular quotations:
#include "../include/ginkgo/c_api.h"
* @param _name Name of the datatype of the array | ||
* | ||
*/ | ||
#define DEFINE_ARRAY_OVERLOAD(_ctype, _cpptype, _name) \ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In addition to putting them in c_api.cpp
, I would also recommend prefixing all of them with GKO_
.
* @brief A build instruction for declaring gko::array<T> in the C API header | ||
* file | ||
*/ | ||
#define DECLARE_ARRAY_OVERLOAD(_ctype, _cpptype, _name) \ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This macro must have a GKO_
prefix because it's a public-facing header.
* @param _name Name of the datatype of the dense matrix | ||
* | ||
*/ | ||
#define DEFINE_DENSE_OVERLOAD(_ctype, _cpptype, _name) \ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Prefix with GKO_
and put it into the c_api.cpp
file.
* @brief A build instruction for declaring gko::matrix::Dense<T> in the C API | ||
* header file | ||
*/ | ||
#define DECLARE_DENSE_OVERLOAD(_ctype, _cpptype, _name) \ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
GKO_
Prefix
* @param _name_dense Name of the datatype of the dense matrix for apply | ||
* function | ||
*/ | ||
#define DEFINE_CSR_OVERLOAD(_ctype_value, _ctype_index, _cpptype_value, \ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
GKO_
and move it to c_api.cpp
* @brief A build instruction for declaring gko::matrix::Csr<Tv,Ti> in the C API | ||
* header file | ||
*/ | ||
#define DECLARE_CSR_OVERLOAD(_ctype_value, _ctype_index, _cpptype_value, \ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
GKO_
prefix
/* ---------------------------------------------------------------------- | ||
* C memory management | ||
* ---------------------------------------------------------------------- */ | ||
void c_char_ptr_free(char* ptr); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you need this as a public function, it must be prefixed (for functions, you seem to use ginkgo_
).
I also have a general question: Should we add some form of CI to check if the API is still working? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess I would prefer this file to be in include/ginkgo/extension
folder.
This PR adds the initial support of the C API implementation for interoperating with other programming languages, such as Fortran, Python, and Julia. The language linkage with key word
extern "c"
is used to enable the interfacing.C API Design:
std::dynamic_pointer_cast
to avoid code duplicationChanges:
include/ginkgo/c_api.h
(define macros, declares function/structs) and source filecore/c_api.cpp
(concretize definitions of declared functions that internally callsginkgo
)cmake/install_helpers.cmake
andcore/CMakeLists.txt
to include the C APIExample Usage:
ccall
through the from Clang generated Julia side api.jl, which internally executes compiled dynamic libraries of ginkgo. It supports both locally compiled dynamic libraries or ones that are hosted under an artifact package ginkgo_jll.jl.