//--------------------------------------------------------------------- // ACOVEA -- Analysis of Compiler Options Via Evolution Algorithm // // acovea.cpp // // Class definitions for the ACOVEA algorithm //--------------------------------------------------------------------- // // Copyright 2003, 2004, 2005 Scott Robert Ladd // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2 of the License, or // (at your option) any later version. // // This program 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 General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the // Free Software Foundation, Inc. // 59 Temple Place - Suite 330 // Boston, MA 02111-1307, USA. // //----------------------------------------------------------------------- // // For more information on this software package, please visit // Scott's web site, Coyote Gulch Productions, at: // // http://www.coyotegulch.com // //----------------------------------------------------------------------- #include "acovea.h" using namespace acovea; #include "libcoyotl/realutil.h" #include "libcoyotl/sortutil.h" using namespace libcoyotl; #include #include #include #include #include #include #include #include #include #include #include using namespace std; // the expat XML parsing library #include "expat.h" // global constant static const double BOGUS_RUN_TIME = 1000000000.0; //---------------------------------------------------------- // abstract definition of a application option or switch // creation constructor option::option(bool a_enabled) : m_enabled(a_enabled) { // nada } // copy constructor option::option(const option & a_source) : m_enabled(a_source.m_enabled) { // nada } // assignment option & option::operator = (const option & a_source) { m_enabled = a_source.m_enabled; return *this; } // randomize settings of this option void option::randomize() { m_enabled = (g_random.get_rand_real2() < 0.5); } // mutate this option void option::mutate() { m_enabled = !m_enabled; } // virtual destructor (does nothing unless overridden) option::~option() { // nada }; //---------------------------------------------------------- // an option that is just a string // creation constructor simple_option::simple_option(const string & a_name, bool a_enabled) : option(a_enabled), m_name(a_name) { // nada } simple_option::simple_option(const char * a_name, bool a_enabled) : option(a_enabled), m_name(a_name) { // nada } // copy constructor simple_option::simple_option(const simple_option & a_source) : option(a_source), m_name(a_source.m_name) { // nada } // assignment operator simple_option & simple_option::operator = (const simple_option & a_source) { option::operator = (a_source); m_name = a_source.m_name; return *this; } // clone option * simple_option::clone() { return new simple_option(*this); } //---------------------------------------------------------- // value settings tracker // constructor tuning_settings_tracker::tuning_settings_tracker(const tuning_option & a_option) : m_values() { // add value to list m_values.push_back(a_option.is_enabled() ? a_option.get_value() : 0); } // copy constructor tuning_settings_tracker::tuning_settings_tracker(const tuning_settings_tracker & a_source) : m_values(a_source.m_values) { // nada } // assignment tuning_settings_tracker & tuning_settings_tracker::operator = (const tuning_settings_tracker & a_source) { m_values = a_source.m_values; } // get a string representing this settings tracker string tuning_settings_tracker::get_settings_text() { stringstream result; int average = 0; int nonzero_count = 0; if (m_values.size() > 0) { for (vector::iterator value = m_values.begin(); value != m_values.end(); ++value) { result << (*value) << " "; average += (*value); if ((*value) > 0) ++nonzero_count; } if (nonzero_count > 0) average /= nonzero_count; else average = 0; result << ", average = " << average << " across " << nonzero_count << " populations"; } return result.str(); } // accumulate values settings_tracker & tuning_settings_tracker::operator += (const settings_tracker & tracker) { try { // this will crash is a non-value setting_tracker is the argument const vector & new_values = (dynamic_cast(tracker)).m_values; // add new values to list for (vector::const_iterator value = new_values.begin(); value != new_values.end(); ++value) m_values.push_back(*value); } catch (...) { cerr << "mixed tracker types in tuning_settings_tracker\n"; } return *this; } //---------------------------------------------------------- // an option or switch that requires an integer argument // creation constructor tuning_option::tuning_option(const string & a_name, bool a_enabled, int a_default, int a_min_value, int a_max_value, int a_step, char a_separator) : simple_option(a_name, a_enabled), m_value(a_default), m_default(a_default), m_min_value(a_min_value), m_max_value(a_max_value), m_step(a_step), m_separator(a_separator) { // make sure min < max if (m_min_value > m_max_value) { int temp = m_min_value; m_min_value = m_max_value; m_max_value = temp; } // step must be >= 1; if (m_step < 1) m_step = 1; // possibly adjust value to randomize populations size_t choice = g_random.get_rand_index(3); switch (choice) { case 0: m_value += m_step; break; case 1: m_value -= m_step; break; } // ensure value is inside specified range if (m_value < m_min_value) m_value = m_min_value; if (m_value > m_max_value) m_value = m_max_value; } // copy constructor tuning_option::tuning_option(const tuning_option & a_source) : simple_option(a_source), m_value(a_source.m_value), m_default(a_source.m_default), m_min_value(a_source.m_min_value), m_max_value(a_source.m_max_value), m_step(a_source.m_step), m_separator(a_source.m_separator) { // nada } // assignment operator tuning_option & tuning_option::operator = (const tuning_option & a_source) { simple_option::operator = (a_source); m_value = a_source.m_value; m_default = a_source.m_default; m_min_value = a_source.m_min_value; m_max_value = a_source.m_max_value; m_step = a_source.m_step; m_separator = a_source.m_separator; return *this; } // get the string for this option string tuning_option::get() const { stringstream result; result << m_name << m_separator << m_value; return result.str(); } // mutate this option void tuning_option::mutate() { // select our mutation if (g_random.get_rand_real2() < 0.5) option::mutate(); else { // mutate value of this option, up or down randomly if (g_random.get_rand_real2() < 0.5) m_value -= m_step; else m_value += m_step; // ensure value stays within bounds if (m_value < m_min_value) m_value = m_min_value; if (m_value > m_max_value) m_value = m_max_value; } } // clone option * tuning_option::clone() { return new tuning_option(*this); } //---------------------------------------------------------- // an option or switch set to one of several mutually-exclusive states // creation constructor enum_option::enum_option(const vector & a_choices, bool a_enabled) : option(a_enabled), m_choices(a_choices), m_setting(g_random.get_rand_index(a_choices.size())) { // nada } // creation constructor enum_option::enum_option(const char ** a_choices, size_t a_num_choices, bool a_enabled) : option(a_enabled), m_choices(), m_setting(g_random.get_rand_index(a_num_choices)) { for (int n = 0; n < a_num_choices; ++n) m_choices.push_back(string(a_choices[n])); } // creation constructor enum_option::enum_option(const char * a_choices, bool a_enabled) : option(a_enabled), m_choices(), m_setting(0) { // start tokenizing char * choices = strdup(a_choices); char * token = strtok(choices,"|"); while (token != NULL) { // add token to choice list m_choices.push_back(string(token)); // next token token = strtok(NULL,"|"); } m_setting = g_random.get_rand_index(m_choices.size()); free(choices); } // copy constructor enum_option::enum_option(const enum_option & a_source) : option(a_source), m_choices(a_source.m_choices), m_setting(a_source.m_setting) { // nada } // assignment enum_option & enum_option::operator = (const enum_option & a_source) { option::operator = (a_source); m_choices = a_source.m_choices; m_setting = a_source.m_setting; } // clone option * enum_option::clone() { return new enum_option(*this); } // get the string for this option string enum_option::get() const { return m_choices[m_setting]; } // randomize settings of this option void enum_option::randomize() { // randomize enabled m_enabled = (g_random.get_rand_real2() < 0.5); // randomize setting m_setting = g_random.get_rand_index(m_choices.size()); } // mutate this option void enum_option::mutate() { // select our mutation if (g_random.get_rand() & 1) option::mutate(); else { // mutate setting of this option if (m_choices.size() == 2) { if (m_setting == 0) m_setting = 1; else m_setting = 0; } else { int new_setting = m_setting; // find a different setting while (new_setting == m_setting) new_setting = g_random.get_rand_index(m_choices.size()); m_setting = new_setting; } } } // virtual destructor (does nothing unless overridden) enum_option::~enum_option() { // nada } //---------------------------------------------------------- // a vector of options // constructor chromosome::chromosome() { // nada } // copy constructor chromosome::chromosome(const chromosome & a_source) { // add elements from source for (int n = 0; n < a_source.size(); ++n) push_back(a_source[n]->clone()); } // assignment chromosome & chromosome::operator = (const chromosome & a_source) { // remove all elements from the vector clear(); // add elements from source for (int n = 0; n < a_source.size(); ++n) push_back(a_source[n]->clone()); return *this; } // destructor chromosome::~chromosome() { // free memory allocated in elements of vector for (vector