The User's Manual
The Ninf-G remote libraries are implemented as executable programs
which contain network stub routine as its main routine, and spawned
off by the Gram component on the Ninf-G system. We call such
executable programs Ninf-G executable associated with its
name, and executes the found executable, sets up an appropriate
communication with the client. The stub routine handles the
communication to the Ninf-G system and its client, including argument
marshalling. The underlying executable can be written in any existing
scientific languages such as Fortran, C, etc, as long as it can be
executed in the host.
To register and publish your numerical libraries and computational
resource, you first should provide interface information about those
numerical libraries and prepares the Ninf-G executable by performing
the following task.
- Write a interface information of the numerical libraries you
wish to register using interface description language called
Ninf-G IDL. The complete syntax of Ninf-G IDL is described in the
Appendix.
The following code is a sample Ninf-G IDL for matrix multiplication.
Module mmul;
Define dmmul(long mode_in int n, mode_in double A[n][n],
mode_in double B[n][n], mode_out double C[n][n])
"... description ..."
Required "libxxx.o" /* specify library including this routine. */
Calls "C" dmmul(n,A,B,C); /* Use C calling convention. */
As such, you should provide the following information in the Ninf-G IDL file.
- Module name.
- Interface Information(marshaling information) of each library routine.
- Information to make whole Module.
- Compile a Ninf-G IDL with Ninf-G generator and generates a stub main
routine which bridges each numerical librarary and our Ninf-G
runtime routines, and Makefile to compile the whole program.
% ns_gen <IDL File>
This will make a Makefile named "module".mak, some
"_stub_XXX.c" files, XML files, and LDIF files.
- Make Ninf-G executables by typing
% make -f <module_name>.mak
This will make some "_stub_XXX" files
- Copy the LDIF file within the directory ${GLOBUS_DEPLOY_PATH}/etc/gridrpc by
typing,
make -f <module_name>.mak install
The LDIF file looks like the following,
dn: rpcFuncname=mmul/dmmul, sw=GridRPC
objectclass: GridRPCEntry
hn:
rpcFuncname: mmul/dmmul
module: mmul
entry: dmmul
path: /usr/local/ninf/ninf-g/tests/mmul/_stub_dmmul
stub:: PGZ1bmN0aW9uICB2ZXJzaW9uPSIyMjEuMDAwMDAwIiA+PGZ1
PSJwaSIgZW50cnk9InBpX3RyaWFsIiAvPiA8YXJnIGRhdGFfdHlwZT
cGU9ImluIiA+CjwvYXJnPgo8YXJnIGRhdGFfdHlwZT0ibG9uZyIgbW
Pgo8L2FyZz4KPGFyZyBkYXRhX3R5cGU9ImxvbmciIG1vZGVfdHlwZT
NOTES for dynamic linkage of the Globus shared libraries:
The Globus dynamic linking libraries (shared libraries) must be linked
with the Ninf-G stub executables. In order to enable this, set the
shared library linkage path appropriately according to the system on
which the Ninf-G stubs are installed.
For example, this is done by adding the location of Globus libraries
(${GLOBUS_LOCATION}/lib) to the environment variable
${LD_LIBRARY_PATH} of the Globus Gatekeeper spawning via inetd, or on
Linux, add (${GLOBUS_LOCATION}/lib) in /etc/ld.so.conf.
Before starting, be sure that the environment variables
GLOBUS_LOCATION (for GT2) or GLOBUS_INSTALL_PATH (for Globus Ver.1), and NS_DIR are defined appropriately.
Since the original Ninf client programming interface was designed to be as
language independent as possible, we have developed a variety of
programming interfaces such as C, Fortran, Java, and Lisp. The concept
of the Ninf-G system is the same. Currently the Ninf-G system supports
the C interface, and we are in the process of building the Java
interface and other language bindings. Ninf-G provides both Grid RPC native API (GRPC API) and Ninf
compatible API (Ninf API). Ninf API is a full-compatible API with
Ninf version 1 which provides simple and easy programming interface to
programmers. GRPC API provides lower level and flexible programming
interface to programmers. According to the requirements, application
programmers can build Grid-enabled applications using either GRPC API
or Ninf API. In this section, we introduce you several representative
functions using C interface for both GRPC API
and Ninf API. The complete API reference is described in the Appendix.
Initialize
This function read configuration file for your client program and
set system parameters for Ninf-G.
main (int argc, char **argv) {
char *conf_file = argv[1];
grpc_initialize(conf_file);
...
Synchronous Call
The synchronous call to Ninf-G from C is the easiest to
implement, just call the function, grpc_call() .
This function returns an error code. It takes as arguments the name
of a problem and the list of input data and output data. These inputs
are listed according to the calling sequence defined in the
corresponding Ninf IDL. The more detailed information on the Ninf-G IDL
are described in the section called Ninf-G IDL
The C prototype of the function is
grpc_call(grpc_function_handle_t *handle, <argument list>)
where *handle is a pointer to the handle to the numerical library on
the Ninf-G system. Let us resume our example of the call to a simple
matrix multiplication. In C, the local function to this caliculation
looks like
mmul(double *A, double *B, double *C),
Meanwhile, the equivalent synchronous call to Ninf-G in C is
grpc_function_handle_t *handle;
grpc_function_handle_init(&handle, "ninf.apgrid.org",
3030, "lib/mmul");
status = grpc_call(&handle, A, B, C);
As such, you should initialize a function handle to the Ninf-G remote
library using grpc_function_handle_init which takes as
arguments a server name, port number, and a module name of the
library.
Asynchronous Call
The standard grpc_call() RPC is synchronous in that the client waits
until the completion of the computation on the server side. For
task-parallel execution, Ninf-G facilitates several asynchronous call
APIs. For example, the most basic asynchronous call
int grpc_async_call(grpc_function_handle_t *handle,
<argument list>)
It is almost identical to grpc_call except that it returns immediately after
all the arguments have been sent. The return value is the session ID
of the asynchronous call; the ID is used for various synchronizations
such as waiting for the return value of the call.
There are several calls for synchronization. The most basic is the
grpc_wait(int sessionID);
grpc_wait_all();
,
grpc_wait() is the function with which
we wait for the result of the asynchronous
call with the supplied session ID. grpc_wait_all() waits for all
preceding asynchronous invocations made.
After developing the Ninf Client Application by the use of the
programming interface, what you need to do for running the application
are listed here.
-
Compile your Ninf-G client application using ns_client_gen
${NG_DIR}/bin/ns_client_gen -g -o test_client test_client.c
-
Write a configuration file as the following.
#
# Ninf-G Client Config File
#
port = 24001 # specify the port number
serverhost = brain.a02.aist.go.jp # Globus node
ldaphost = brain.a02.aist.go.jp # LDAP Host
ldapport = 2135 # LDAP Port number
-
Obtain a Globus proxy
Before submitting any jobs to the Ninf-G system, you need to run the
following command and get a proxy certificate, which allows you to
utilize any Ninf-G numerical libraries on the Globus resource without
reentering your pass phrase while your proxy is active.
We assume you have already obtained a Globus Certificate
from the Globus Certificate Authority and you are in the resources'
grid mapfiles.
% grid-proxy-init
You can set the time for the proxy to be in effect; use
% grid-proxy-init -hours (nhours)
If you wish to determine your proxy status, use grid-proxy-info
-all to display the contents or test the status of your proyx.
-
Run the Ninf-G client
% ./test_client config.cl
Since the Ninf-G system is built on top of the Globus, you can
directly take advantage of the Globus commands for
managing the submitted jobs such as checking, killing, and cleaning.
We give you very quick overview of the Globus commands, and more
detailed explanation can be seen in the Globus manual.
Checking my job
% globus-job-run <hostname> /bin/ps -u <username>
When you submit a job to the batch scheduler, enter
globus-job-status followed by the job contact string URL.
% globus-job-submit $lt;hostname$gt; $lt;command$gt;
https://$lt;hostname$gt;:3031/342265377/
% globus-job-status https://ninf.apgrid.org:3031/942265377/
The different status are PENDING(waiting in the queue),
ACTIVE(running), SUSPENDED, DONE, and FAILED.
Canceling/Cleaning a Job
If you interrupt the globusrun or globus-job-run
process(by entering CTRL-C or sending it a SIGINT), your jobs should
automatically be canceld.
Initialize
This function parse argument list for your client program and retrieve
arguments for Ninf-G system. This function returns new argc value.
Here is an example showing typical usage.
main (int argc, char ** argv){
argc = Ninf_parse_arg(argc, argv);
...
Synchronous call
This function calls Ninf function on a remote server.
The first argument specifies server and function.
Here is an example that calls "mmul" function.
Ninf_call("mmul", n, A, B, C);
You can omit the server name and port.
In such case, a default server will be used.
Default server can be specified by environment variable "NINF_SERVER"
and "NINF_SERVER_PORT", or Ninf_parse_arg.
This function returns 0 if succeed, returns -1 if failed.
Asynchronous Call
This function is almost same as Ninf_call, but it returns immediately.
Using this function, you can invoke several sessions simultaneously.
It returns non-negative ID if succeed, returns -1 if failed.
id = Ninf_call_async("mmul", n, A, B, C);
There are several calls for synchronization. The most basic is the
Ninf_wait(int sessionID);
Ninf_wait_all();
,
Ninf_wait() is the function with which
we wait for the result of the asynchronous
call with the supplied session ID. grpc_wait_all() waits for all
preceding asynchronous invocations made.
As mentioned above, Ninf_call() is the client interface to
the Ninf compute and database servers. In order to illustrate the programming
interface with an example, let us consider a simple matrix multiply routine
in C programs with the following interface:
double A[N][N],B[N][N],C[N][N]; /* declaration */
....
dmmul(N,A,B,C); /* calls matrix multiply, C = A * B */
When the dmmul routine is available on a Ninf server,
the client program can call the remote library using Ninf_call ,
in the following manner:
Ninf_call("dmmul",N,A,B,C); /* call remote Ninf library on server */
Here, dmmul is the name of library registered as a Ninf
executable on a server, and N,A,B,C are the same arguments.
As we see here, the client user only needs to specify the name
of the function as if he were making a local function call;
Ninf_call() automatically determines the function arity and
the type of each argument, appropriately marshals the arguments, makes
the remote call to the server, obtains the results, places the
results in the appropriate argument, and returns to the client.
In this way, the Ninf RPC is designed to give the users an
illusion that arguments are shared between the client and the server.
The reader may also notice that the physical location of the Ninf server
is not specified in the example. Ninf provides a variety of ways for
the client to specify the server and its registered library:
- Specify server with an environment variable.
- Directly specify server and library with an URL of the Ninf executable.
To realize such simplicity in the client programming interface,
we designed Ninf RPC so that client function call obtains all the
interface information regarding the called library function at runtime
from the server. Although this will cost an extra network round trip
time, we judged that typical scientific applications are both
compute and data intensive such that the overhead should be small
enough. The interface information includes:
- the number of parameters.
- argument types.
- access mode of arguments (read or write).
- size of arguments.
- argument marshaling information.
- how to send and receive data from/to the Ninf server.
The client function call requests the interface
information of the calling function to the Ninf server, which in turn
returns the registered Ninf executable interface information to the client.
The client library then interprets and marshals the arguments on the
stack according to the supplied information. For variable-sized array
arguments, the IDL must specify an expression that includes the input
scalar arguments whereby the size of the arrays can be computed.
This design is in contrast to traditional RPCs, where stub generation
is done on the client side at compile time. As a result of dynamic
interface acquisition, Ninf RPC does not require such compile-time
activities at all, relieving the users from any code maintenance.
[2] describes the structure of the
interface information and the protocol in detail.
In the above example, the client function call sends the input arrays,
A and B,
whose size is computed by the parameter N .
The Ninf server invokes the Ninf executable of dmmul library,
and forwards the input data to it.
When the computation is done, the result is sent back to the client
through the server. The client function call stores the returned data at
the location pointed by the argument, C.
The Ninf RPC may also be invoked asynchronously to exploit network-wide parallelism.
It is possible to issue the request to a Ninf server, continue with the other
computation, and poll for the request later. Multiple RPC requests to different
servers are also possible. For this reason, the asynchronous Ninf PRC is an
important feature for parallel programming.
Next