// Berkeley Open Infrastructure for Network Computing // http://boinc.berkeley.edu // Copyright (C) 2005 University of California // // This 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 2.1 of the License, or (at your option) any later version. // // This software 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. // // To view the GNU Lesser General Public License visit // http://www.gnu.org/copyleft/lesser.html // or write to the Free Software Foundation, Inc., // 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #ifdef _WIN32 #include "boinc_win.h" #endif #ifndef _WIN32 #include "config.h" #include #include #include #endif #ifdef HAVE_SYS_SOCKET_H #include #endif #include "parse.h" #include "util.h" #include "error_numbers.h" #include "client_msgs.h" #include "client_state.h" #include "network.h" #include "log_flags.h" #include "time_stats.h" // exponential decay constant. // The last 10 days have a weight of 1/e; // everything before that has a weight of (1-1/e) const float ALPHA = (SECONDS_PER_DAY*10); //const float ALPHA = 60; // for testing bool BOINC_OUTAGE::is_recent() const { return gstate.now - 60 * SECONDS_PER_DAY < end; } TIME_STATS::TIME_STATS() { last_update = 0; first = true; on_frac = 1; connected_frac = 1; active_frac = 1; cpu_efficiency = 1; } // Update time statistics based on current activities // NOTE: we don't set the state-file dirty flag here, // so these get written to disk only when other activities // cause this to happen. Maybe should change this. // void TIME_STATS::update(bool is_active) { double dt, w1, w2; if (last_update == 0) { // this is the first time this client has executed. // Assume that everything is active on_frac = 1; connected_frac = 1; active_frac = 1; first = false; last_update = gstate.now; } else { dt = gstate.now - last_update; if (dt <= 10) return; w1 = 1 - exp(-dt/ALPHA); // weight for recent period w2 = 1 - w1; // weight for everything before that // (close to zero if long gap) // the following always returns UNKNOWN, // but leave it here for now // int connected_state = get_connected_state(); if (first) { // the client has just started; this is the first call. // on_frac *= w2; first = false; BOINC_OUTAGE outage; outage.start = last_update; outage.end = gstate.now; outages.push_back(outage); gstate.set_client_state_dirty("Outage"); } else { on_frac = w1 + w2*on_frac; if (connected_frac < 0) connected_frac = 0; switch (connected_state) { case CONNECTED_STATE_NOT_CONNECTED: connected_frac *= w2; break; case CONNECTED_STATE_CONNECTED: connected_frac *= w2; connected_frac += w1; break; case CONNECTED_STATE_UNKNOWN: connected_frac = -1; } active_frac *= w2; if (is_active) { active_frac += w1; if (inactive_start) { BOINC_OUTAGE outage; outage.start = inactive_start; outage.end = gstate.now; outages.push_back(outage); gstate.set_client_state_dirty("Outage"); inactive_start = 0; } } else if (inactive_start == 0){ inactive_start = gstate.now; } } last_update = gstate.now; if (log_flags.time_debug) { msg_printf(0, MSG_INFO, "[time_debug] dt %f w2 %f on %f; active %f; conn %f", dt, w2, on_frac, active_frac, connected_frac ); } } } void TIME_STATS::update_cpu_efficiency(double cpu_wall_time, double cpu_time) { double old_cpu_efficiency = cpu_efficiency; if (cpu_wall_time < .01) return; double w = exp(-cpu_wall_time/SECONDS_PER_DAY); double e = cpu_time/cpu_wall_time; if (e<0) { return; } cpu_efficiency = w*cpu_efficiency + (1-w)*e; if (log_flags.cpu_sched_debug){ msg_printf(0, MSG_INFO, "[cpu_sched_debug] CPU efficiency old %f new %f wall %f CPU %f w %f e %f", old_cpu_efficiency, cpu_efficiency, cpu_wall_time, cpu_time, w, e ); } } // Write XML based time statistics // int TIME_STATS::write(MIOFILE& out, bool to_server) { out.printf( "\n" " %f\n" " %f\n" " %f\n" " %f\n", on_frac, connected_frac, active_frac, cpu_efficiency ); if (!to_server) { out.printf( " %f\n", last_update ); } #if 0 // too much text. Maybe just send the longest outage? // if (outages.size()) { out.printf(" \n"); unsigned int i; for (i=0; i\n" " %f\n" " %f\n" " \n", outages[i].start, outages[i].end ); } } out.printf(" \n"); } #endif out.printf("\n"); return 0; } // Parse XML based time statistics, usually from client_state.xml // int TIME_STATS::parse(MIOFILE& in) { char buf[256]; while (in.fgets(buf, 256)) { if (match_tag(buf, "")) return 0; else if (parse_double(buf, "", last_update)) continue; else if (parse_double(buf, "", on_frac)) continue; else if (parse_double(buf, "", connected_frac)) continue; else if (parse_double(buf, "", active_frac)) continue; else if (parse_double(buf, "", cpu_efficiency)) { if (cpu_efficiency < 0) cpu_efficiency = 1; if (cpu_efficiency > 1) cpu_efficiency = 1; continue; } else if (match_tag(buf, "")){ while(in.fgets(buf, 256)) { if (match_tag(buf, "")) break; else if (match_tag(buf, "")) { BOINC_OUTAGE outage; while (in.fgets(buf, 256)) { if (match_tag(buf, "")) { outages.push_back(outage); break; } else if (parse_double(buf, "", outage.start)) continue; else if (parse_double(buf, "", outage.end)) continue; } } } } else { if (log_flags.unparsed_xml) { msg_printf(0, MSG_INFO, "[unparsed_xml] TIME_STATS::parse(): unrecognized: %s\n", buf ); } } } return ERR_XML_PARSE; } double TIME_STATS::get_longest_boinc_outage() const { unsigned int i; double longest_outage = 0; for (i=0; i longest_outage) longest_outage = outage_length; } } return longest_outage; } const char *BOINC_RCSID_472504d8c2 = "$Id$";