rpc_lesson3¶
Two models run in a client-server, remote procedure call (RPC) communication pattern. The client model client sends requests and receives response to/from the server model server via the deprecated call method. The server model receives requests and send responses. The client model receives request data from a file and send responses to a file. In the case of both models, yggdrasil auto-wraps functions with interface calls at runtime. This example demostrates the RPC pattern through the use of the client_of and is_server model parameters and the RPC interface classes/functions in conjunction with automated wrapping of model functions, including the use of the global_scope interface parameter when autowrapping functions that contain interface calls themselves.
C Version¶
Model Code:
1#include <stdio.h>
2
3int model_function(char *in_buf, uint64_t length_in_buf,
4 char **out_buf, uint64_t *length_out_buf) {
5 printf("server(C): %s\n", in_buf);
6 length_out_buf[0] = length_in_buf;
7 out_buf[0] = (char*)malloc(length_in_buf);
8 memcpy(out_buf[0], in_buf, length_in_buf);
9 out_buf[0][length_in_buf] = '\0';
10 return 0;
11};
1#include "YggInterface.h"
2#include <stdio.h>
3
4
5int model_function(char* in_buf, uint64_t length_in_buf,
6 char** out_buf, uint64_t* length_out_buf) {
7 // The WITH_GLOBAL_SCOPE macro is required to ensure that the comm persists
8 // between function calls
9 WITH_GLOBAL_SCOPE(yggRpc_t rpc = yggRpcClient("server_client", "%s", "%s"));
10 printf("client(C): %s (length = %d)\n", in_buf, (int)(length_in_buf));
11 int ret = rpcCallRealloc(rpc, in_buf, length_in_buf, out_buf, length_out_buf);
12 if (ret < 0) {
13 printf("client(C): RPC CALL ERROR\n");
14 return -1;
15 }
16 return 0;
17}
Model YAML:
1---
2
3model:
4 name: server
5 language: c
6 args: ./src/server.c
7 function: model_function
8 is_server: # Creates a RPC server queue called "server"
9 input: in_buf
10 output: out_buf
11 inputs: in_buf
12 outputs: out_buf
1model:
2 name: client
3 language: c
4 args: ./src/client.c
5 function: model_function
6 client_of: server
7 inputs:
8 name: in_buf
9 default_file:
10 name: ./Input/input.txt
11 filetype: ascii
12 outputs:
13 name: out_buf
14 default_file:
15 name: ./client_output.txt
16 in_temp: true
C++ Version¶
Model Code:
1#include <iostream>
2
3int model_function(char *in_buf, uint64_t length_in_buf,
4 char* &out_buf, uint64_t &length_out_buf) {
5 std::cout << "server(C++): " << in_buf << std::endl;
6 length_out_buf = length_in_buf;
7 out_buf = (char*)realloc(out_buf, length_in_buf);
8 memcpy(out_buf, in_buf, length_in_buf);
9 out_buf[length_in_buf] = '\0';
10 return 0;
11};
1#include "YggInterface.hpp"
2#include <iostream>
3
4
5int model_function(char *in_buf, uint64_t length_in_buf,
6 char* &out_buf, uint64_t &length_out_buf) {
7 // The WITH_GLOBAL_SCOPE macro is required to ensure that the comm persists
8 // between function calls
9 WITH_GLOBAL_SCOPE(YggRpcClient rpc("server_client", "%s", "%s"));
10 std::cout << "client(C++): " << in_buf << " (length = " << length_in_buf << ")" << std::endl;
11 int ret = rpc.callRealloc(4, in_buf, length_in_buf, &out_buf, &length_out_buf);
12 if (ret < 0) {
13 std::cout << "client(C++): RPC CALL ERROR" << std::endl;
14 return -1;
15 }
16 return 0;
17}
Model YAML:
1---
2
3model:
4 name: server
5 language: c++
6 args: ./src/server.cpp
7 function: model_function
8 is_server: True # Creates a RPC server queue called "server"
1model:
2 name: client
3 language: c++
4 args: ./src/client.cpp
5 function: model_function
6 client_of: server
7 inputs:
8 name: in_buf
9 default_file:
10 name: ./Input/input.txt
11 filetype: ascii
12 outputs:
13 name: out_buf
14 default_file:
15 name: ./client_output.txt
16 in_temp: true
Fortran Version¶
Model Code:
1function model_function(in_buf, out_buf) result(out)
2 character(len=*), intent(in) :: in_buf
3 character(len=:), pointer :: out_buf
4 logical :: out
5 write(*, '("server(Fortran): ",A)') in_buf
6 out = .true.
7 allocate(character(len=len(in_buf)) :: out_buf)
8 out_buf = in_buf
9end function model_function
1function model_function(in_buf, out_buf) result(ret)
2 character(len=*), intent(in) :: in_buf
3 type(yggchar_r) :: out_buf
4 logical :: ret
5 type(yggcomm) :: rpc
6 WITH_GLOBAL_SCOPE(rpc = ygg_rpc_client("server_client"))
7 write(*, '("client(F): ",A," (length = ",I3,")")') in_buf, len(in_buf)
8 ret = ygg_rpc_call_realloc(rpc, yggarg(in_buf), yggarg(out_buf))
9 if (.not.ret) then
10 write(*, '("client(F): RPC CALL ERROR")')
11 stop 1
12 end if
13end function model_function
Model YAML:
1---
2
3model:
4 name: server
5 language: fortran
6 args: ./src/server.f90
7 function: model_function
8 is_server: True # Creates a RPC server queue called "server"
1model:
2 name: client
3 language: fortran
4 args: ./src/client.f90
5 function: model_function
6 client_of: server
7 inputs:
8 name: in_buf
9 default_file:
10 name: ./Input/input.txt
11 filetype: ascii
12 outputs:
13 name: out_buf
14 default_file:
15 name: ./client_output.txt
16 in_temp: true
Julia Version¶
Model Code:
1using Yggdrasil
2using Printf
3
4function model_function(in_buf)
5 @printf("server(Julia): %s\n", in_buf)
6 out_buf = in_buf
7 return out_buf
8end
1using Yggdrasil
2using Printf
3
4function model_function(in_buf)
5 # The global_scope keyword is required to ensure that the comm persists
6 # between function calls
7 rpc = Yggdrasil.YggInterface("YggRpcClient", "server_client", global_scope=true)
8 @printf("client(Julia): %s\n", in_buf)
9 ret, result = rpc.call(in_buf)
10 if (!ret)
11 error("client(Julia): RPC CALL ERROR")
12 end
13 out_buf = result
14 return out_buf
15end
Model YAML:
1---
2
3model:
4 name: server
5 language: julia
6 args: ./src/server.jl
7 function: model_function
8 is_server: True # Creates a RPC server queue called "server"
1model:
2 name: client
3 language: julia
4 args: ./src/client.jl
5 function: model_function
6 client_of: server
7 inputs:
8 name: in_buf
9 default_file:
10 name: ./Input/input.txt
11 filetype: ascii
12 outputs:
13 name: out_buf
14 default_file:
15 name: ./client_output.txt
16 in_temp: true
Matlab Version¶
Model Code:
1function out_buf = server(in_buf)
2 fprintf('server(Matlab): %s\n', in_buf);
3 out_buf = in_buf;
4end
1function out_buf = client(in_buf)
2 % The global_scope keyword is required to ensure that the comm persists
3 % between function calls
4 rpc = YggInterface('YggRpcClient', 'server_client', 'global_scope', true);
5 disp(sprintf('client(Matlab): %s', in_buf));
6 [ret, result] = rpc.call(in_buf);
7 if (~ret);
8 error('client(Matlab): RPC CALL ERROR');
9 end;
10 out_buf = result;
11end
Model YAML:
1---
2
3model:
4 name: server
5 language: matlab
6 args: ./src/server.m
7 function: server # matlab requires function to match file
8 is_server: True # Creates a RPC server queue called "server"
1model:
2 name: client
3 language: matlab
4 args: ./src/client.m
5 function: client # Matlab requires the same name
6 client_of: server
7 inputs:
8 name: in_buf
9 default_file:
10 name: ./Input/input.txt
11 filetype: ascii
12 outputs:
13 name: out_buf
14 default_file:
15 name: ./client_output.txt
16 in_temp: true
Python Version¶
Model Code:
1def model_function(in_buf):
2 print("server(Python): %s" % in_buf)
3 out_buf = in_buf
4 return out_buf
1from yggdrasil.languages.Python.YggInterface import YggRpcClient
2
3
4def model_function(in_buf):
5 # The global_scope keyword is required to ensure that the comm persists
6 # between function calls
7 rpc = YggRpcClient('server_client', global_scope=True)
8 print("client(Python): %s" % in_buf)
9 ret, result = rpc.call(in_buf)
10 if not ret:
11 raise RuntimeError('client(Python): RPC CALL ERROR')
12 out_buf = result
13 return out_buf
Model YAML:
1model:
2 name: server
3 language: python
4 args: ./src/server.py
5 function: model_function
6 is_server: True
1model:
2 name: client
3 language: python
4 args: ./src/client.py
5 function: model_function
6 client_of: server
7 inputs:
8 name: in_buf
9 default_file:
10 name: ./Input/input.txt
11 filetype: ascii
12 outputs:
13 name: out_buf
14 default_file:
15 name: ./client_output.txt
16 in_temp: true
R Version¶
Model Code:
1model_function <- function(in_buf) {
2 fprintf('server(R): %s', in_buf)
3 out_buf <- in_buf
4 return(out_buf);
5}
1model_function <- function(in_buf) {
2 # The global_scope keyword is required to ensure that the comm persists
3 # between function calls
4 rpc <- YggInterface('YggRpcClient', 'server_client', global_scope=TRUE)
5 print(sprintf("client(R): %s", in_buf))
6 c(ret, result) %<-% rpc$call(in_buf)
7 if (!ret) {
8 stop('client(R): RPC CALL ERROR')
9 }
10 out_buf <- result[[1]]
11 return(out_buf)
12}
Model YAML:
1---
2
3model:
4 name: server
5 language: R
6 args: ./src/server.R
7 function: model_function
8 is_server: True # Creates a RPC server queue called "server"
1model:
2 name: client
3 language: R
4 args: ./src/client.R
5 function: model_function
6 client_of: server
7 inputs:
8 name: in_buf
9 default_file:
10 name: ./Input/input.txt
11 filetype: ascii
12 outputs:
13 name: out_buf
14 default_file:
15 name: ./client_output.txt
16 in_temp: true