boinc/doc/api.html

215 lines
7.6 KiB
HTML

<h2>The BOINC Application Programming Interface</h2>
<h3>Porting Your Application to BOINC</h3>
<p>
Porting an application to function on the BOINC platform is fairly
easy. The BOINC API provides a set of C/C++ functions which should be
called as described below to ensure proper integration with the BOINC
core client. If the provided BOINC API is not used, users should
write their own. The only aspect of the API that is required is
to resolve BOINC soft links, ignoring the rest of the features should
still allow the application to function, albeit somewhat unpredictably.
<ol>
<li>
<b>BOINC Initialization</b>
<br>
Functions:
<ul>
<li>
<tt>void boinc_init(APP_IN& ai, int opengl_support);</tt>
</li>
</ul>
<br>
When the application starts, it should call <tt>boinc_init</tt> before
performing any computation. <tt>boinc_init</tt> performs several important
functions necessary for proper communication between the application and
the core client. First, it reads the general preferences from the BOINC
core client, which contain information about graphics, checkpointing,
and CPU time. Based on these preferences, it initializes timers for
graphics redraw and checkpoint purposes, and prepares the OpenGL window
(if desired) for graphics display. If the application supports OpenGL
graphics, <tt>opengl_support</tt> should be 1 and an appropriate <tt>draw_gl</tt>
function should be included in the application. If the application does not
support OpenGL graphics, <tt>opengl_support</tt> should be 0 and an empty
<tt>draw_gl</tt> should be included.
<p>
</li>
<li>
<b>Resolving BOINC Soft Links</b>
<br>
Functions:
<ul>
<li>
<tt>int boinc_resolve_link(char *file_name, char *resolved_name);</tt>
</li>
</ul>
<br>
Because there are many different ways of creating file links depending on
the platform and file system, BOINC uses a simple XML based linking scheme.
An example of a link would be a file containing only the following XML tag:
<p>
<tt>&lt;soft_link&gt;../../myproject.com/workunit_12345&lt;/soft_link&gt;</tt>
</p>
As an example, if the code currently uses <tt>fopen</tt> in this manner:
<p>
<tt>
file = fopen("my_file", "r");
</tt>
</p>
then the proper way to use <tt>boinc_resolve_link</tt> would be as follows:
<p>
<tt>
char resolved_name[512];<br>
boinc_resolve_link("my_file",resolved_name);<br>
file = fopen(resolved_name,"r");<br>
</tt>
<p>
The application should call <tt>boinc_resolve_link</tt> every time it needs
to access a file.
</li>
<li>
<b>OpenGL Graphics in BOINC</b>
<br>
Functions:
<ul>
<li>
<tt>void draw_opengl();</tt>
</li><li>
<tt>void gl_done();</tt>
</li>
</ul>
<br>
BOINC provides functionality which automatically sets up an OpenGL window, the
application porter needs only write a <tt>draw_gl</tt> function. The <tt>draw_gl</tt>
function is called when graphics need to be drawn to the screen. At the completion
of the <tt>draw_gl</tt> function, <tt>gl_done</tt> should be called to ensure the
graphics are properly blitted to the screen. If a non-OpenGL graphics library
is to be used, it is the applications responsibility to set it up and use the
refresh period passed via <tt>boinc_init</tt> in <tt>APP_IN</tt>.
<p>
</li>
<li>
<b>The APP_IN Structure</b>
<br>
Members:
<ul>
<li>
<tt>char app_prefrences[4096];</tt>
</li><li>
<tt>APP_IN_GRAPHICS graphics;</tt>
</li><li>
<tt>double checkpoint_period;</tt>
</li><li>
<tt>double poll_period;</tt>
</li><li>
<tt>double cpu_time;</tt>
</li>
</ul>
<br>
The APP_IN structure is passed via <tt>boinc_init()</tt> on initialization.
The <tt>app_preferences</tt> string contains any user preferences. The <tt>graphics</tt> structure
contains information about the OpenGL graphics settings. The api will initialize
timers such that the period of <tt>time_to_checkpoint()</tt> is <tt>checkpoint_period</tt>. The <tt>poll_period</tt> states how often the core client will poll the application for state information. The <tt>cpu_time</tt> member contains the number of seconds previously spent working on the current work unit.
<p>
</li>
<li>
<b>The APP_OUT Structure</b>
<br>
Members:
<ul>
<li>
<tt>double percent_done;</tt>
</li><li>
<tt>double cpu_time_at_checkpoint;</tt>
</li><li>
<tt>bool checkpoint_completed;</tt>
</li>
</ul>
<br>
The APP_OUT structure is passed via <tt>checkpoint_completed()</tt> and <tt>app_completed()</tt>. The only member expected to be filled in by the application is <tt>percent_done</tt>. THe other members will be filled in by the api. The <tt>cpu_time_at_checkpoint</tt> contains the cpu time elapsed in this instance of the application, which can be combined with the <tt>cpu_time</tt> from the APP_IN structure for total cpu time spent on this work unit.
<p>
</li>
<li>
<b>The MFILE Class</b>
<br>
Functions:
<ul>
<li>
<tt>int MFILE::open(char* path, char* mode);</tt>
</li><li>
<tt>int MFILE::_putchar(char);</tt>
</li><li>
<tt>int MFILE::puts(char*);</tt>
</li><li>
<tt>int MFILE::printf(char* format, ...);</tt>
</li><li>
<tt>size_t MFILE::write(const void *,size_t,size_t);</tt>
</li><li>
<tt>int MFILE::close();</tt>
</li><li>
<tt>int MFILE::flush();</tt>
</li>
</ul>
<br>
The MFILE class provides (nearly) atomic file writing. Most modern operating systems
do not write information to files immediately, it is often buffered for a period and
parts of the buffer are slowly written out. If an application unexpectedly quits
(due to power failure, a crash, etc), the
contents of a file may be missing or partially complete. It is also wise to call
<tt>flush</tt> for each MFILE when checkpointing, since the application state
at a checkpoint should be restartable.
<p>
</li>
<li>
<b>Checkpointing and Saving State</b>
<br>
Functions:
<ul>
<li>
<tt>bool time_to_checkpoint( void );</tt>
</li><li>
<tt>void checkpoint_completed(APP_OUT&);</tt>
</li>
</ul>
<br>
Most distributed computations require a significant amount of time
(several hours or more) for each unit of work. For this reason, it is
wise to periodically write out the current
state of the computation to disk in case of an unexpected quit or
shutdown. This is known as "checkpointing". Your application should
call <tt>time_to_checkpoint</tt> whenever it reaches a point where it can safely
save the state of the
computation, usually (indicate common places here). The state of the computation
should include everything required to start the computation again at the same
place it was checkpointed. For example, if the application contains a main loop
which is run many times during the course of the computation, checkpointing could
simply save the current iteration of the loop (reword this). If <tt>time_to_checkpoint</tt>
returns true, then go ahead and save the state, flush the MFILEs, etc. When the
checkpoint is complete call <tt>checkpoint_completed</tt>, which will take care of
extra housecleaning and communication with the core client. If possible, the APP_OUT
structure passed to <tt>checkpoint_completed</tt> should contain a rough estimate of the
percentage complete. When your
application starts up, it should read the state file to determine where
to begin computation. The period between checkpoints is user controllable (though
the default is x seconds), so it is
unwise to write your application assuming a specific checkpointing period.
<p>
</li>
<li>
<b>Cleaning Up</b>
<br>
Functions:
<ul>
<li>
<tt>int app_completed(APP_OUT& ao);</tt>
</li>
</ul>
<br>
When the application has completed it should call <tt>app_completed()</tt>, then exit.
<tt>app_completed()</tt> will take care of BOINC related housekeeping, such as telling
the core client that the application has completed, and closing OpenGL windows.
<p>
</li>
</ol>