XPRD C
The program example runprimedistr.c below shows how to run the model prime.mos remotely using the XPRD C library (NB: this program corresponds to the mmjobs distributed computing example runprimedistr.mos from Section Distributed computing). At first sight, the reader might be reminded of the Mosel C libraries presented in Chapter C interface. However, there are two major additions besides the change of the prefixes from XPRM to XPRD:
- We need to connect to a remote machine and create a new Mosel instance (XPRDmosel) prior to working with any Mosel models. Remote machines are specified by their name or IP address, the empty string in the present example indicates that we want to use the local machine.
- The submodel is executed in an independent process and we therefore need to wait for its termination.
In summary, the standard execution sequence for Mosel models of compile load run is augmented to connect – compile load run wait in the context of distributed computing (this remark equally applies to submodels launched via mmjobs).
Instead of simply waiting for the submodel to terminate, the program below waits for 2 seconds and if no termination event message has been received from the Mosel model, it is stopped by the application. After termination of the submodel (either by finishing its calculations within less than 2 seconds or stopped by the parent model) the application reports the full event information and also displays the termination status and the exit value of the Mosel model. Unloading a model explicitly as shown here is only really necessary in larger applications that continue after the termination of the submodel, so as to free the memory used by it.
#include <stdio.h> #include <stdlib.h> #include "xprd.h" int main(int argv,char *args[]) { XPRDcontext xprd; XPRDmosel moselInst; XPRDmodel modPrime, evsender; double evvalue; int evclass; xprd=XPRDinit(); /* Create an XPRD context */ /* Open connection to a remote node: "" means the node running this program */ moselInst=XPRDconnect(xprd, "", NULL, NULL, NULL, 0); /* Compile the model file */ XPRDcompmod(moselInst, "", "rmt:prime.mos", "rmt:prime.bim", ""); /* Load BIM into the remote instance */ modPrime=XPRDloadmod(moselInst, "rmt:prime.bim"); XPRDrunmod(modPrime, "LIMIT=50000"); /* Start execution and */ XPRDwaitevent(xprd,2); /* wait 2 seconds for an event */ if (XPRDqueueempty(xprd)==1) /* No event has been sent... */ { printf("Model too slow: stopping it!\n"); XPRDstoprunmod(modPrime); /* ... stop the model, then wait */ XPRDwaitevent(xprd,-1); } XPRDgetevent(xprd, &evsender, &evclass, &evvalue); /* Get the event */ printf("Event value: %g sent by model %d\n", evvalue, XPRDgetnum(evsender)); printf("Exit status: %d\n", XPRDgetstatus(modPrime)); printf("Exit code : %d\n", XPRDgetexitcode(modPrime)); XPRDunloadmod(modPrime); /* Unload the model */ XPRDdisconnect(moselInst); /* Disconnect remote instance */ XPRDfinish(xprd); /* Terminate XPRD */ remove("prime.bim"); /* Clean up temporary files */ return 0; }
In this example, we assume that the model source is saved on the local machine running XPRD, and the BIM file is written back to this machine (indicated by the I/O driver prefix rmt: in the 'compile' and 'load' functions that are executed on the remote instance). Alternatively, we might choose to save the BIM file on the remote machine, e.g. in memory (shmem:primebim) or in Mosel's temporary directory (tmp:prime.bim).
Exchanging data with the model
A typical programming task when working with remote models is the retrieval of results into the calling application. In this section we show how to use XPRD functionality for retrieving data that is written by a Mosel model in an initializations block into the XPRD program. The choice of the method for exchanging data usually depends on the particular system setup (write access rights) and the volume of data to be communicated (memory usage). Data in Mosel format can be output
- on the remote machine running Mosel
- in memory
- as a physical file
- on the local machine running XPRD
- in memory
- as a physical file
Case 1a is implemented in the program version runprimeiodistr.c printed below. Case 1b is obtained by removing the shmem: prefix from the file name, for example, the setting
OUTPUTFILE=bin:tmp:resdata
will create a file resdata in Mosel's temporary directory. Cases 2a and 2b could use the setting
OUTPUTFILE=bin:rmt:resdata
For the implementation of case 2b we simply replace the calls to the XPRD remote file access functions by the standard C library functions fopen, fread, and fclose. Somewhat more work is required for the implementation of case 2a: the program needs to define an XPRD file manager to handle the data in memory—an example implementation is provided in the file runprimeiodistr2.c.
All implementation versions share the use of the bin: I/O driver and they all define the same function show_solution that decodes Mosel's binary format and displays the solution values. Using Mosel's binary format is recommended (though not a necessity) in distributed applications—it is platform-independent and uses less space than the standard text format.
The program example of the previous section stops the Mosel model with a call to XPRDstoprunmod. We now replace this hard stop by sending the user event `STOPMOD' to the submodel: instead of immediately terminating the submodel this event is intercepted by the submodel and makes it interrupt its calculations and write out the current solution. To make sure that the submodel is actually running at the point where we sent the `STOPMOD' event, we have also introduced a 'MODREADY' event sent from the submodel to its parent to indicate the point of time when it starts the calculations (with heavy operating system loads the actual submodel start may be delayed).
The Mosel model primeio.mos remains the same as shown in Section Exchanging data between models.
#include <stdio.h> #include <stdlib.h> #include <string.h> #include "xprd.h" #include "bindrv.h" #define STOPMOD 2 /* Identifier for "Stop submodel" user event */ #define MODREADY 3 /* Identifier for "Submodel ready" user event */ int main(int argv,char *args[]) { XPRDcontext xprd; XPRDmosel moselInst; XPRDmodel modPrime, evsender; double evvalue; int evclass; XPRDfile f; xprd=XPRDinit(); /* Create an XPRD context */ /* Open connection to a remote node: "" means the node running this program */ moselInst=XPRDconnect(xprd, "", NULL, NULL, NULL, 0); /* Compile the model file */ XPRDcompmod(moselInst, "", "rmt:primeio.mos", "tmp:primeio.bim", ""); /* Load the bim file into the remote instance */ modPrime=XPRDloadmod(moselInst, "tmp:primeio.bim"); /* Disable submodel output */ XPRDsetdefstream(moselInst, modPrime, XPRD_F_WRITE, "null:"); /* Start execution */ XPRDrunmod(modPrime, "LIMIT=50000,OUTPUTFILE=bin:shmem:resdata"); XPRDwaitevent(xprd,0); /* Wait for an event */ XPRDgetevent(xprd, &evsender, &evclass, &evvalue); /* Get the event */ if (evclass != MODREADY) /* Check the event class */ { printf("Problem with submodel run"); return 1; } XPRDwaitevent(xprd,2); /* Wait 2 seconds for an event */ if (XPRDqueueempty(xprd)==1) /* No event has been sent */ { printf("Model too slow: stopping it!\n"); XPRDsendevent(modPrime, STOPMOD, 0); /* Stop the model, then */ XPRDwaitevent(xprd,-1); /* wait for its termination */ } /* Open the output file, retrieve and display the solution data */ f=XPRDfopen(moselInst, "shmem:resdata", XPRD_F_BINARY|XPRD_F_INPUT, NULL,0); show_solution(my_read,f); XPRDfclose(f); XPRDunloadmod(modPrime); /* Unload the model */ XPRDdisconnect(moselInst); /* Disconnect remote instance */ XPRDfinish(xprd); /* Terminate XPRD */ return 0; }
Once the submodel has terminated we read its solution from the location specified in the model parameter OUTPUTFILE and display the results. The subroutine show_solution uses functions from the bindrv library that is provided with XPRD to decode Mosel's binary format. The output file read by this routine has the same structure as the correponding text file in Mosel format, for example:
NumP: 6 SPrime: [ 2 3 5 7 11 13 ]
Since XPRD and bindrv expect different signatures for their reading functions, we also define a wrapper function my_read.
/**** Wrapper function for 'bindrv' ****/ static size_t my_read(void *buf, size_t size, size_t nmemb, void *ctx) { size_t s,a; long t; s=size*nmemb; a=0; while(s>0) { t=XPRDfread(ctx,(char*)buf+a,s); if(t<=0) break; else { a+=t; s-=t; } } return a/size; } /**** Using bindrv: Decode the binary file and display its contents ****/ void show_solution(size_t (*doread)(void *,size_t,size_t,void*), void *rctx) { s_bindrvctx bdrv; int *solarr; int size,i,n; char *str; bdrv=bindrv_newreader(doread,rctx); /* Initialize binreader */ i=size=0; solarr=NULL; while(bindrv_nexttoken(bdrv)>=0) { bindrv_getctrl(bdrv,&n); /* 'label' (marker) */ bindrv_getstring(bdrv,&str); /* Read a string */ if(strcmp(str,"NumP")==0) { free(str); bindrv_getint(bdrv,&size); /* Read an integer */ printf("( %d prime numbers)\n", size); if(size>0) /* Prepare array to receive values */ solarr=malloc(sizeof(int)*size); else break; } else if(strcmp(str,"SPrime")==0) { free(str); bindrv_getctrl(bdrv,&n); /* [ (start marker) */ while(bindrv_nexttoken(bdrv)==BINDRV_TYP_INT) { /* Read integers */ bindrv_getint(bdrv,&(solarr[i++])); } bindrv_getctrl(bdrv,&n); /* ] (end marker) */ } else { printf("Unexpected label: %s\n", str); free(str); exit(1); } } bindrv_delete(bdrv); /* Release bin reader */ /* Print the set of prime numbers */ printf("Prime numbers={"); for(i=0;i<size;i++) printf(" %d",solarr[i]); printf("}\n"); free(solarr); /* Clean up */ }
© 2001-2025 Fair Isaac Corporation. All rights reserved. This documentation is the property of Fair Isaac Corporation (“FICO”). Receipt or possession of this documentation does not convey rights to disclose, reproduce, make derivative works, use, or allow others to use it except solely for internal evaluation purposes to determine whether to purchase a license to the software described in this documentation, or as otherwise set forth in a written software license agreement between you and FICO (or a FICO affiliate). Use of this documentation and the software described in it must conform strictly to the foregoing permitted uses, and no other use is permitted.