Во время своей работы сервер BOINC должен постоянно генерировать какие-либо задания, которые потом будут отправляться на обработку клиентам. Для этих целей используется специальный демон-генератор. Чаще всего он называется work_generator.
Пример генератора можно найти по адресу ~/server_stable/sched/sample_work_generatr.cpp.
Файл этот можно менять в соответствии с потребностями.
Рассмотрим простой пример сборки и запуска генератора.
0. Если сервер BOINC запущен, следует его остановить ~/projects/test/bin/stop (~/projects/test/ - домашняя директория рабочего проекта)
1. Идем в ~/server_stable/sched/
2. Собираем генератор: make. Могут понадобиться права суперюзера. Есть готовый MakeFile для сборки примеров. Его можно использовать и для сборки переписанного генератора. Файл достаточно большой и запутанный. Можно в нем поковыряться и извлечь только то, что касается генератора. Можно так же переписать под себя (мне например понадобилось добавить флаг -lntl в переменную СXXFLAGS для подключения библиотеки NTL). Повторюсь, и без правки всё будет прекрасно собираться.
3. В результате получим 2 файла: sample_work_generator.o (исполняемый) и sample_work_generator(скрипт). Эти файлы копируем в ~/projects/test/bin/
4. Теперь надо подправить конфигурационный файл проекта: ~/projects/test/config.xml. В самом конце этого файла находится описание запускаемых при старте проекта демонов. Добавляем туда следующее:
5. Запускаем проект ~/projects/test/bin/start
Теперь во время работы сервера BOINC будут постоянно генерироваться задания. В папку ~/projects/test/download запишутся файлы заданий, который будут потом отправляться клиентам. Также задания будут зарегистрированы в базе BOINC в таблице workunit.
Теперь рассмотрим пример файла-генератора.
Пример генератора можно найти по адресу ~/server_stable/sched/sample_work_generatr.cpp.
Файл этот можно менять в соответствии с потребностями.
Рассмотрим простой пример сборки и запуска генератора.
0. Если сервер BOINC запущен, следует его остановить ~/projects/test/bin/stop (~/projects/test/ - домашняя директория рабочего проекта)
1. Идем в ~/server_stable/sched/
2. Собираем генератор: make. Могут понадобиться права суперюзера. Есть готовый MakeFile для сборки примеров. Его можно использовать и для сборки переписанного генератора. Файл достаточно большой и запутанный. Можно в нем поковыряться и извлечь только то, что касается генератора. Можно так же переписать под себя (мне например понадобилось добавить флаг -lntl в переменную СXXFLAGS для подключения библиотеки NTL). Повторюсь, и без правки всё будет прекрасно собираться.
3. В результате получим 2 файла: sample_work_generator.o (исполняемый) и sample_work_generator(скрипт). Эти файлы копируем в ~/projects/test/bin/
4. Теперь надо подправить конфигурационный файл проекта: ~/projects/test/config.xml. В самом конце этого файла находится описание запускаемых при старте проекта демонов. Добавляем туда следующее:
<daemon> <cmd> sample_work_generator -d 3 </cmd> </daemon>Там подобные конструкции уже должны быть. Надо и эту добавить по аналогии. Флаги -d 3 означают, что команда запускает демон с третьим уровнем отладки.
5. Запускаем проект ~/projects/test/bin/start
Теперь во время работы сервера BOINC будут постоянно генерироваться задания. В папку ~/projects/test/download запишутся файлы заданий, который будут потом отправляться клиентам. Также задания будут зарегистрированы в базе BOINC в таблице workunit.
Теперь рассмотрим пример файла-генератора.
#include <unistd.h>
#include <cstdlib>
#include <string>
#include <cstring>
#include "boinc_db.h"
#include "error_numbers.h"
#include "backend_lib.h"
#include "parse.h"
#include "util.h"
#include "svn_version.h"
#include "sched_config.h"
#include "sched_util.h"
#include "sched_msgs.h"
#include "str_util.h"
#define CUSHION 1000 //количество неотосланных результатов, при котором новые
// задания не формируются
#define REPLICATION_FACTOR 2
char* wu_template;
DB_APP app;
int start_time;
int seqno;
//создать одно задание
int make_job(ZZ &num) {
DB_WORKUNIT wu;
char name[256], path[256];
const char* infiles[1];
int retval;
//генерируем уникальное име файла-задания
sprintf(name, "s_%d_%d", start_time, seqno++);
//определяем физический путь к файлу
retval = config.download_path(name, path);
if (retval) return retval;
//записываем в файл что надо
ofstreamfile file(path);
file << num;
file.close();
//заполняем параметры задания
wu.clear();
wu.appid = app.id;
strcpy(wu.name, name);
wu.rsc_fpops_est = 1e12;
wu.rsc_fpops_bound = 1e14;
wu.rsc_memory_bound = 1e8;
wu.rsc_disk_bound = 1e8;
wu.delay_bound = 86400;
wu.min_quorum = REPLICATION_FACTOR;
wu.target_nresults = REPLICATION_FACTOR;
wu.max_error_results = REPLICATION_FACTOR*4;
wu.max_total_results = REPLICATION_FACTOR*8;
wu.max_success_results = REPLICATION_FACTOR*4;
infiles[0] = name;
//регестрируем задание в BOINC (записываем в базу)
return create_work(
wu,
wu_template,
"templates/uc_result",
config.project_path("templates/uc_result"),
infiles,
1,
config
);
}
//основная функция генерации заданий
void main_loop() {
int retval;
ZZ curr_num=to_ZZ("5");
while (1) {
check_stop_daemons(); //проверяем, запущен ли сервер
int n;
retval = count_unsent_results(n, 0); //количество неотосланных заданий
if (n > CUSHION) { //если не отправленных заданий слишком много - ожидаем
sleep(60);
} else {
int njobs = (CUSHION-n)/REPLICATION_FACTOR;
log_messages.printf(MSG_DEBUG,
"Making %d jobs\n", njobs
);
for (int i=0; i<njobs; i++) {
retval = make_job(curr_num);
while (1) {
curr_num++;
if (curr_num%2==0 || curr_num%3==0 || curr_num%5==0)
continue;
break;
}
if (retval) { //код ошибки
log_messages.printf(MSG_CRITICAL,
"can't make job: %d\n", retval
);
exit(retval);
}
}
sleep(5);
}
}
}
int main(int argc, char** argv) {
int i, retval;
start_num=0;
end_num = 0;
for (i=1; i<argc; i++) {
if (is_arg(argv[i], "d")) {
if (!argv[++i]) {
log_messages.printf(MSG_CRITICAL, "%s requires an argument\n\n", argv[--i]);
exit(1);
}
int dl = atoi(argv[i]);
log_messages.set_debug_level(dl);
if (dl == 4) g_print_queries = true;
}
else {
log_messages.printf(MSG_CRITICAL, "unknown command line argument: %s\n\n", argv[i]);
usage(argv[0]);
exit(1);
}
}
retval = config.parse_file();
if (retval) {
log_messages.printf(MSG_CRITICAL,
"Can't parse config.xml: %s\n", boincerror(retval)
);
exit(1);
}
retval = boinc_db.open(
config.db_name, config.db_host, config.db_user, config.db_passwd
);
if (retval) {
log_messages.printf(MSG_CRITICAL, "can't open db\n");
exit(1);
}
if (app.lookup("where name='uppercase'")) {
log_messages.printf(MSG_CRITICAL, "can't find app\n");
exit(1);
}
if (read_file_malloc(config.project_path("templates/uc_wu"), wu_template)) {
log_messages.printf(MSG_CRITICAL, "can't read WU template\n");
exit(1);
}
start_time = time(0);
seqno = 0;
log_messages.printf(MSG_NORMAL, "Starting\n");
main_loop();
}
Комментариев нет:
Отправить комментарий