Во время своей работы сервер 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(); }
Комментариев нет:
Отправить комментарий