diff --git a/checkin_notes b/checkin_notes index f4b0d1279d..0bdc10812d 100644 --- a/checkin_notes +++ b/checkin_notes @@ -8476,3 +8476,15 @@ Rom 29 Nov 2010 vboxwrapper.cpp win_build/ vboxwrapper.vcproj + +David 29 Nov 2010 + - add support for making wrappers for Rappture: + https://nanohub.org/infrastructure/rappture/ + + samples/ + wrappture/ + wrappture.cpp,h + wrappture_example.cpp + Makefile + wrapper/ + wrapper.cpp diff --git a/samples/wrapper/wrapper.cpp b/samples/wrapper/wrapper.cpp index fdd2db9acb..bd4468559b 100644 --- a/samples/wrapper/wrapper.cpp +++ b/samples/wrapper/wrapper.cpp @@ -565,6 +565,9 @@ int main(int argc, char** argv) { for (i=0; i. + +#include +#include +#include +#ifdef _WIN32 +#include "boinc_win.h" +#include "win_util.h" +#else +#include +#include +#include +#include +#include "procinfo.h" +#endif + +#include "boinc_api.h" +#include "diagnostics.h" +#include "filesys.h" +#include "parse.h" +#include "str_util.h" +#include "str_replace.h" +#include "util.h" +#include "error_numbers.h" + +#include "wrappture.h" + +#define POLL_PERIOD 1.0 + +using std::vector; +using std::string; + +struct TASK { + string application; + string stdin_filename; + string stdout_filename; + string stderr_filename; + string checkpoint_filename; + // name of task's checkpoint file, if any + string fraction_done_filename; + // name of file where app will write its fraction done + string command_line; + double weight; + // contribution of this task to overall fraction done + double final_cpu_time; + double starting_cpu; + // how much CPU time was used by tasks before this in the job file + bool suspended; + double wall_cpu_time; + // for estimating CPU time on Win98/ME and Mac +#ifdef _WIN32 + HANDLE pid_handle; + DWORD pid; + HANDLE thread_handle; + struct _stat last_stat; // mod time of checkpoint file +#else + int pid; + struct stat last_stat; +#endif + bool stat_first; + bool poll(int& status); + int run(int argc, char** argv); + void kill(); + void stop(); + void resume(); + double cpu_time(); + inline bool has_checkpointed() { + bool changed = false; + if (checkpoint_filename.size() == 0) return false; + struct stat new_stat; + int retval = stat(checkpoint_filename.c_str(), &new_stat); + if (retval) return false; + if (!stat_first && new_stat.st_mtime != last_stat.st_mtime) { + changed = true; + } + stat_first = false; + last_stat.st_mtime = new_stat.st_mtime; + return changed; + } + inline double fraction_done() { + if (fraction_done_filename.size() == 0) return 0; + FILE* f = fopen(fraction_done_filename.c_str(), "r"); + if (!f) return 0; + double frac; + int n = fscanf(f, "%lf", &frac); + fclose(f); + if (n != 1) return 0; + if (frac < 0) return 0; + if (frac > 1) return 1; + return frac; + } +}; + +APP_INIT_DATA aid; +double fraction_done, checkpoint_cpu_time; + +#ifdef _WIN32 +// CreateProcess() takes HANDLEs for the stdin/stdout. +// We need to use CreateFile() to get them. Ugh. +// +HANDLE win_fopen(const char* path, const char* mode) { + SECURITY_ATTRIBUTES sa; + memset(&sa, 0, sizeof(sa)); + sa.nLength = sizeof(sa); + sa.bInheritHandle = TRUE; + + if (!strcmp(mode, "r")) { + return CreateFile( + path, + GENERIC_READ, + FILE_SHARE_READ, + &sa, + OPEN_EXISTING, + 0, 0 + ); + } else if (!strcmp(mode, "w")) { + return CreateFile( + path, + GENERIC_WRITE, + FILE_SHARE_WRITE, + &sa, + OPEN_ALWAYS, + 0, 0 + ); + } else if (!strcmp(mode, "a")) { + HANDLE hAppend = CreateFile( + path, + GENERIC_WRITE, + FILE_SHARE_WRITE, + &sa, + OPEN_ALWAYS, + 0, 0 + ); + SetFilePointer(hAppend, 0, NULL, FILE_END); + return hAppend; + } else { + return 0; + } +} +#endif + +void slash_to_backslash(char* p) { + while (1) { + char* q = strchr(p, '/'); + if (!q) break; + *q = '\\'; + } +} + +int TASK::run(int argct, char** argvt) { + string stdout_path, stdin_path, stderr_path; + char app_path[1024], buf[256]; + + if (checkpoint_filename.size()) { + boinc_delete_file(checkpoint_filename.c_str()); + } + if (fraction_done_filename.size()) { + boinc_delete_file(fraction_done_filename.c_str()); + } + + strcpy(buf, application.c_str()); + char* p = strstr(buf, "$PROJECT_DIR"); + if (p) { + p += strlen("$PROJECT_DIR"); + sprintf(app_path, "%s%s", aid.project_dir, p); + } else { + boinc_resolve_filename(buf, app_path, sizeof(app_path)); + } + + // Append wrapper's command-line arguments to those in the job file. + // + for (int i=1; i" + +// the following runs in a thread and parses the app's stdout file, +// looking for progress tags +// +void* parse_app_stdout(void*) { + char buf[8192]; + FILE* f = boinc_fopen("rappture_stdout.txt", "r"); + + while (1) { + if (fgets(buf, sizeof(buf), f)) { + if (strstr(buf, PROGRESS_MARKER)) { + fraction_done = atof(buf+strlen(PROGRESS_MARKER))/100; + } + } else { + boinc_sleep(1.); + } + } +} + +int create_parser_thread() { +#ifdef _WIN32 + DWORD parser_thread_id; + if (!CreateThread(NULL, 0, parse_app_stdout, 0, 0, &parser_thread_id)) { + return ERR_THREAD; + } +#else + pthread_t parser_thread_handle; + pthread_attr_t thread_attrs; + pthread_attr_init(&thread_attrs); + pthread_attr_setstacksize(&thread_attrs, 16384); + int retval = pthread_create( + &parser_thread_handle, &thread_attrs, parse_app_stdout, NULL + ); + if (retval) { + return ERR_THREAD; + } +#endif + return 0; +} + +int boinc_run_rappture_app(const char* program, const char* cmdline) { + TASK task; + int retval; + BOINC_OPTIONS options; + + memset(&options, 0, sizeof(options)); + options.main_program = true; + options.check_heartbeat = true; + options.handle_process_control = true; + boinc_init_options(&options); + + memset(&task, 0, sizeof(task)); + task.application = program; + task.command_line = cmdline; + task.stdout_filename = "rappture_stdout.txt"; + + retval = task.run(0, 0); + create_parser_thread(); + while (1) { + int status; + if (task.poll(status)) { + if (status) { + boinc_finish(EXIT_CHILD_FAILED); + } + break; + } + poll_boinc_messages(task); + send_status_message(task, fraction_done, checkpoint_cpu_time); + boinc_sleep(POLL_PERIOD); + } + return 0; +} diff --git a/samples/wrappture/wrappture.h b/samples/wrappture/wrappture.h new file mode 100644 index 0000000000..cf02f394ae --- /dev/null +++ b/samples/wrappture/wrappture.h @@ -0,0 +1,18 @@ +// This file is part of BOINC. +// http://boinc.berkeley.edu +// Copyright (C) 2010 University of California +// +// BOINC is free software; you can redistribute it and/or modify it +// under the terms of the GNU Lesser General Public License +// as published by the Free Software Foundation, +// either version 3 of the License, or (at your option) any later version. +// +// BOINC is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with BOINC. If not, see . + +extern int boinc_run_rappture_app(const char* program, const char* cmdline); diff --git a/samples/wrappture/wrappture_example.cpp b/samples/wrappture/wrappture_example.cpp new file mode 100644 index 0000000000..ecc922d94b --- /dev/null +++ b/samples/wrappture/wrappture_example.cpp @@ -0,0 +1,107 @@ +// ---------------------------------------------------------------------- +// EXAMPLE: Fermi-Dirac function in C. +// +// This simple example shows how to use Rappture within a simulator +// written in C. +// ====================================================================== +// AUTHOR: Derrick Kearney, Purdue University +// Copyright (c) 2004-2008 Purdue Research Foundation +// +// See the file "license.terms" for information on usage and +// redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES. +// ====================================================================== + +//#include "rappture.h" + +#include +#include +#include +#include + +#include "error_numbers.h" +#include "boinc_api.h" +#include "wrappture.h" + +#define RPLIB_OVERWRITE 0 +struct RpLibrary{}; +RpLibrary* rpLibrary(char*){return NULL;} +void rpGetString(RpLibrary*, const char*, const char**){} +double rpConvertDbl(const char*, const char*, int*){return 0;} +void rpPutString (RpLibrary*, const char*, const char*, int){} +void rpResult(RpLibrary*); + +int main(int argc, char * argv[]) { + + RpLibrary* lib = NULL; + + const char* data = NULL; + char line[100]; + + double T = 0.0; + double Ef = 0.0; + double E = 0.0; + double dE = 0.0; + double kT = 0.0; + double Emin = 0.0; + double Emax = 0.0; + double f = 0.0; + + int err = 0; + + // create a rappture library from the file filePath + lib = rpLibrary(argv[1]); + + if (lib == NULL) { + // cannot open file or out of memory + printf("FAILED creating Rappture Library\n"); + return(1); + } + + + rpGetString(lib,"input.number(temperature).current",&data); + T = rpConvertDbl(data, "K", &err); + if (err) { + printf ("Error while retrieving input.number(temperature).current\n"); + return(1); + } + + + rpGetString(lib,"input.number(Ef).current",&data); + Ef = rpConvertDbl(data, "eV", &err); + if (err) { + printf ("Error while retrieving input.number(Ef).current\n"); + return(1); + } + + kT = 8.61734e-5 * T; + Emin = Ef - 10*kT; + Emax = Ef + 10*kT; + + E = Emin; + dE = 0.005*(Emax-Emin); + + rpPutString ( lib, + "output.curve(f12).about.label", + "Fermi-Dirac Factor", + RPLIB_OVERWRITE ); + rpPutString ( lib, + "output.curve(f12).xaxis.label", + "Fermi-Dirac Factor", + RPLIB_OVERWRITE ); + rpPutString ( lib, + "output.curve(f12).yaxis.label", + "Energy", + RPLIB_OVERWRITE ); + rpPutString ( lib, + "output.curve(f12).yaxis.units", + "eV", + RPLIB_OVERWRITE ); + + int retval = boinc_run_rappture_app("foobar.exe", "-kT 4.3"); + if (retval == 0) { + boinc_finish(0); + rpResult(lib); + } else { + boinc_finish(EXIT_CHILD_FAILED); + } +}