[[PageOutline]]
= Generating work =
To submit a job:
* Write XML 'template files' that describe the job's input and outputs (typically the same template files can be used for many jobs).
* Create the job's input file(s), and put them in the right places (as determined by the file names) in the [DirHierarchy download directory hierarchy].
* Invoke a BOINC function or script that submits the job.
Once this is done, BOINC takes over: it creates one or more instances of the job, distributes them to client hosts, collects the output files, finds a canonical instance, assimilates the canonical instance, and deletes files.
== Input and output template files ==
An input template file has the form
{{{
0
[ , other attributes]
[ ... ]
0
NAME
[ ... ]
[ -flags xyz ]
[ x ]
[ x ]
[ x ]
[ x ]
[ x ]
[ x ]
[ x ]
[ x ]
[ x ]
[ x ]
[ X ]
}}}
Elements and tags must be on separate lines as shown.
The components are:
, ::
Each pair describes an [BoincFiles#Fileproperties input file] and [BoincFiles#Filereferences the way it's referenced].
::
The command-line arguments to be passed to the main program.
::
The amount of credit to be granted for successful completion of this workunit. Use this only if you know in advance how many FLOPs it will take. Your [ValidationSimple validator] must use get_credit_from_wu() as its compute_granted_credit() function.
Other elements::
[JobIn Work unit attributes]
An output template file has the form
{{{
32768
result.sah
}}}
== Submitting a job manually ==
To move an input file to the download directory, use
{{{
dir_hier_path filename
}}}
which prints the full pathname and creates the directory if needed (run this in the project's root directory). For example:
{{{
cp test_files/12ja04aa `bin/dir_hier_path 12ja04aa`
}}}
copies an input file from the test_files directory to the download directory hierarchy.
To submit a job, run bin/create_work from the project root directory:
{{{
create_work [ arguments] infile_1 ... infile_n
}}}
Mandatory arguments are:
-appname name::
application name
-wu_name name::
workunit name
-wu_template filename::
WU template filename relative to project root; usually in templates/
-result_template filename::
result template filename, relative to project root; usually in templates/
Optional arguments are:
-batch n::
-priority n::
The following [JobIn job parameters] may be passed in the input template,
or as command-line arguments to create_work,
or not passed at all (defaults will be used)
-command_line "-flags foo"::
-rsc_fpops_est x::
-rsc_fpops_bound x::
-rsc_memory_bound x::
-rsc_disk_bound x::
-delay_bound x::
-min_quorum x::
-target_nresults x::
-max_error_results x::
-max_total_results x::
-max_success_results x::
-additional_xml 'x'::
This can be used to supply, for example, 12.4.
== Submitting jobs from a C++ program ==
BOINC's library provides the functions:
{{{
// convert filename to path in download hierarchy
//
SCHED_CONFIG::download_path(
const char* filename,
char* path,
);
// submit a job
//
int create_work(
DB_WORKUNIT&,
const char* wu_template, // contents, not path
const char* result_template_filename, // relative to project root
const char* result_template_filepath, // absolute or relative to current dir
const char** infiles, // array of input file names
int ninfiles
SCHED_CONFIG&,
const char* command_line = NULL,
const char* additional_xml = NULL
);
}}}
The ''name'' and ''appid'' fields of the DB_WORKUNIT structure must always be initialized.
Other job parameters may be passed either in the DB_WORKUNIT structure or in the input template file (the latter has priority).
=== Making one workunit ===
Here's a program that submits one job (error-checking is omitted for clarity):
{{{
#include "boinc_db.h"
#include "backend_lib.h"
int main() {
DB_APP app;
DB_WORKUNIT wu;
char* wu_template;
char* infiles[] = {"infile"};
char path[1024];
SCHED_CONFIG config;
config.parse_file();
boinc_db.open(config.db_name, config.db_host, config.db_user, config.db_passwd);
app.lookup("where name='myappname'");
// write input file in the download directory
//
config.download_path("infile", path);
FILE* f = fopen(path, "w");
fwrite(f, "random stuff");
fclose(f);
read_file_malloc("templates/input_template.xml", wu_template);
wu.clear(); // zeroes all fields
strcpy(wu.name, "test_name");
wu.appid = app.id;
wu.min_quorum = 2;
wu.target_nresults = 2;
wu.max_error_results = 5;
wu.max_total_results = 5;
wu.max_success_results = 5;
wu.rsc_fpops_est = 1e10;
wu.rsc_fpops_bound = 1e11;
wu.rsc_memory_bound = 1e8;
wu.rsc_disk_bound = 1e8;
wu.delay_bound = 7*86400;
create_work(
wu,
wu_template,
"templates/output_template.xml",
"templates/output_template.xml",
infiles,
1,
config
);
}
}}}
The program must be run in the project directory.
=== Making lots of workunits ===
If you're making lots of workunits (e.g. to do the various parts of a parallel computation) you'll want the workunits to differ either in their input files, their command-line arguments, or both.
For example, let's say you want to run a program on ten input files 'file0', 'file1', ..., 'file9'. You might modify the above program with the following code:
{{{
char filename[256];
char* infiles[1];
infiles[0] = filename;
...
for (i=0; i<10; i++) {
sprintf(filename, "file%d", i);
create_work(
wu,
wu_template,
"templates/output_template.xml",
"templates/output_template.xml",
infiles,
1,
config
);
}
}}}
Note that you only need one workunit template file and one result template file.
Now suppose you want to run a program against a single input file, but with ten command lines, '-flag 0', '-flag 1', ..., '-flag 9'. You might modify the above program with the following code:
{{{
char command_line[256];
...
for (i=0; i<10; i++) {
sprintf(command_line, "-flag %d", i);
create_work(
wu,
wu_template,
"templates/output_template.xml",
"templates/output_template.xml",
infiles,
1,
config,
command_line
);
}
}}}
Again, you only need one input template file and one output template file.
== Example work generators ==
Two work generator programs are supplied with BOINC.
=== Sample work generator ===
Many projects have an essentially infinite supply of work.
This can be handled by a 'flow-controlled work generator'
that tries to maintain a constant number of unsent jobs
(typically a few hundred or thousand).
It does this by periodically querying the BOINC database
to find the number of unsent jobs.
An example of this is sched/sample_work_generator.C.
You can easily modify this program to suit your application.
=== make_work ===
During the testing phase of a project, you may want to replicate a given workunit as needed to maintain a constant supply of work. The daemon program
{{{
make_work -wu_name name [-wu_name name2 ... ] -cushion N
}}}
creates copies of the given workunits (cyclically) as needed to maintain a supply of at least N unsent results. This is useful for testing purposes.
Note: if you run the file_deleter and/or db_purge, the master workunit or its input files may be deleted (which will cause make_work to fail). To avoid this, give the master workunit a name that contains 'nodelete' as a substring. This causes the file_deleter and db_purge to skip over it.
It may be convenient to have a script that recreates the master workunit. For example:
{{{
cp test_workunits/12ja04aa `bin/dir_hier_path 12ja04aa`
bin/create_work -appname setiathome -wu_name sah_nodelete -wu_template templates/setiathome_wu_0 -result_template templates/setiathome_result_0 12ja04aa
}}}