diff options
Diffstat (limited to 'src/base/stats/mysql.cc')
-rw-r--r-- | src/base/stats/mysql.cc | 828 |
1 files changed, 828 insertions, 0 deletions
diff --git a/src/base/stats/mysql.cc b/src/base/stats/mysql.cc new file mode 100644 index 000000000..0fb31f4ce --- /dev/null +++ b/src/base/stats/mysql.cc @@ -0,0 +1,828 @@ +/* + * Copyright (c) 2004-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Nathan Binkert + */ + +#include <cassert> +#include <map> +#include <sstream> +#include <string> +#include <vector> + +#include "base/misc.hh" +#include "base/mysql.hh" +#include "base/statistics.hh" +#include "base/stats/flags.hh" +#include "base/stats/mysql.hh" +#include "base/stats/mysql_run.hh" +#include "base/stats/statdb.hh" +#include "base/stats/types.hh" +#include "base/str.hh" +#include "sim/host.hh" + +using namespace std; + +namespace Stats { + +MySqlRun MySqlDB; + +bool +MySqlConnected() +{ + return MySqlDB.connected(); +} + +void +MySqlRun::connect(const string &host, const string &user, const string &passwd, + const string &db, const string &name, const string &sample, + const string &project) +{ + if (connected()) + panic("can only get one database connection at this time!"); + + mysql.connect(host, user, passwd, db); + if (mysql.error) + panic("could not connect to database server\n%s\n", mysql.error); + + if (mysql.autocommit(false)) + panic("could not set autocommit\n%s\n", mysql.error); + + remove(name); + //cleanup(); + setup(name, sample, user, project); +} + +void +MySqlRun::setup(const string &name, const string &sample, const string &user, + const string &project) +{ + assert(mysql.connected()); + + stringstream insert; + ccprintf(insert, + "INSERT INTO " + "runs(rn_name,rn_sample,rn_user,rn_project,rn_date,rn_expire)" + "values(\"%s\", \"%s\", \"%s\", \"%s\", NOW()," + "DATE_ADD(CURDATE(), INTERVAL 31 DAY))", + name, sample, user, project); + + mysql.query(insert); + if (mysql.error) + panic("could not get a run\n%s\n", mysql.error); + + run_id = mysql.insert_id(); + if (mysql.commit()) + panic("could not commit transaction\n%s\n", mysql.error); +} + +void +MySqlRun::remove(const string &name) +{ + assert(mysql.connected()); + stringstream sql; + ccprintf(sql, "DELETE FROM runs WHERE rn_name=\"%s\"", name); + mysql.query(sql); + if (mysql.error) + panic("could not delete run\n%s\n", mysql.error); + if (mysql.commit()) + panic("could not commit transaction\n%s\n", mysql.error); +} + +void +MySqlRun::cleanup() +{ + assert(mysql.connected()); + + mysql.query("DELETE data " + "FROM data " + "LEFT JOIN runs ON dt_run=rn_id " + "WHERE rn_id IS NULL"); + + if (mysql.commit()) + panic("could not commit transaction\n%s\n", mysql.error); + + mysql.query("DELETE formula_ref " + "FROM formula_ref " + "LEFT JOIN runs ON fr_run=rn_id " + "WHERE rn_id IS NULL"); + + if (mysql.commit()) + panic("could not commit transaction\n%s\n", mysql.error); + + mysql.query("DELETE formulas " + "FROM formulas " + "LEFT JOIN formula_ref ON fm_stat=fr_stat " + "WHERE fr_stat IS NULL"); + + if (mysql.commit()) + panic("could not commit transaction\n%s\n", mysql.error); + + mysql.query("DELETE stats " + "FROM stats " + "LEFT JOIN data ON st_id=dt_stat " + "WHERE dt_stat IS NULL"); + + if (mysql.commit()) + panic("could not commit transaction\n%s\n", mysql.error); + + mysql.query("DELETE subdata " + "FROM subdata " + "LEFT JOIN data ON sd_stat=dt_stat " + "WHERE dt_stat IS NULL"); + + if (mysql.commit()) + panic("could not commit transaction\n%s\n", mysql.error); + + mysql.query("DELETE events" + "FROM events" + "LEFT JOIN runs ON ev_run=rn_id" + "WHERE rn_id IS NULL"); + + if (mysql.commit()) + panic("could not commit transaction\n%s\n", mysql.error); + + mysql.query("DELETE event_names" + "FROM event_names" + "LEFT JOIN events ON en_id=ev_event" + "WHERE ev_event IS NULL"); + + if (mysql.commit()) + panic("could not commit transaction\n%s\n", mysql.error); +} + +void +SetupStat::init() +{ + name = ""; + descr = ""; + type = ""; + print = false; + prereq = 0; + prec = -1; + nozero = false; + nonan = false; + total = false; + pdf = false; + cdf = false; + min = 0; + max = 0; + bktsize = 0; + size = 0; +} + +unsigned +SetupStat::setup() +{ + MySQL::Connection &mysql = MySqlDB.conn(); + + stringstream insert; + ccprintf(insert, + "INSERT INTO " + "stats(st_name, st_descr, st_type, st_print, st_prereq, " + "st_prec, st_nozero, st_nonan, st_total, st_pdf, st_cdf, " + "st_min, st_max, st_bktsize, st_size)" + "values(\"%s\",\"%s\",\"%s\"," + " %d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d)", + name, descr, type, print, prereq, (int)prec, nozero, nonan, + total, pdf, cdf, + min, max, bktsize, size); + + mysql.query(insert); + if (!mysql.error) { + int id = mysql.insert_id(); + if (mysql.commit()) + panic("could not commit transaction\n%s\n", mysql.error); + return id; + } + + stringstream select; + ccprintf(select, "SELECT * FROM stats WHERE st_name=\"%s\"", name); + + mysql.query(select); + MySQL::Result result = mysql.store_result(); + if (!result) + panic("could not find stat\n%s\n", mysql.error); + + assert(result.num_fields() == 16); + MySQL::Row row = result.fetch_row(); + if (!row) + panic("could not get stat row\n%s\n", mysql.error); + + bool tb; + int8_t ti8; + uint16_t tu16; + int64_t ti64; + uint64_t tu64; + + if (name != (char *)row[1]) + panic("failed stat check on %s:name. %s != %s\n", + name, name, row[1]); + + if (descr != (char *)row[2]) + panic("failed stat check on %s:descr. %s != %s\n", + name, descr, row[2]); + + if (type != (char *)row[3]) + panic("failed stat check on %s:type. %s != %s\n", + name, type, row[3]); + + if (!to_number(row[4], tb) || print != tb) + panic("failed stat check on %s:print. %d != %d\n", + name, print, tb); + + if (!to_number(row[6], ti8) || prec != ti8) + panic("failed stat check on %s:prec. %d != %d\n", + name, prec, ti8); + + if (!to_number(row[7], tb) || nozero != tb) + panic("failed stat check on %s:nozero. %d != %d\n", + name, nozero, tb); + + if (!to_number(row[8], tb) || nonan != tb) + panic("failed stat check on %s:nonan. %d != %d\n", + name, nonan, tb); + + if (!to_number(row[9], tb) || total != tb) + panic("failed stat check on %s:total. %d != %d\n", + name, total, tb); + + if (!to_number(row[10], tb) || pdf != tb) + panic("failed stat check on %s:pdf. %d != %d\n", + name, pdf, tb); + + if (!to_number(row[11], tb) || cdf != tb) + panic("failed stat check on %s:cdf. %d != %d\n", + name, cdf, tb); + + if (!to_number(row[12], ti64) || min != ti64) + panic("failed stat check on %s:min. %d != %d\n", + name, min, ti64); + + if (!to_number(row[13], ti64) || max != ti64) + panic("failed stat check on %s:max. %d != %d\n", + name, max, ti64); + + if (!to_number(row[14], tu64) || bktsize != tu64) + panic("failed stat check on %s:bktsize. %d != %d\n", + name, bktsize, tu64); + + if (!to_number(row[15], tu16) || size != tu16) + panic("failed stat check on %s:size. %d != %d\n", + name, size, tu16); + + to_number(row[5], prereq); + uint16_t statid; + to_number(row[0], statid); + return statid; +} + +InsertData::InsertData() +{ + query = new char[maxsize + 1]; + size = 0; + flush(); +} + +InsertData::~InsertData() +{ + delete [] query; +} + +void +InsertData::flush() +{ + if (size) { + MySQL::Connection &mysql = MySqlDB.conn(); + assert(mysql.connected()); + mysql.query(query); + if (mysql.error) + panic("could not insert data\n%s\n", mysql.error); + if (mysql.commit()) + panic("could not commit transaction\n%s\n", mysql.error); + } + + query[0] = '\0'; + size = 0; + first = true; + strcpy(query, "INSERT INTO " + "data(dt_stat,dt_x,dt_y,dt_run,dt_tick,dt_data) " + "values"); + size = strlen(query); +} + +void +InsertData::insert() +{ + if (size + 1024 > maxsize) + flush(); + + if (!first) { + query[size++] = ','; + query[size] = '\0'; + } + + first = false; + + size += sprintf(query + size, "(%u,%d,%d,%u,%llu,\"%f\")", + stat, x, y, MySqlDB.run(), (unsigned long long)tick, + data); +} + +struct InsertSubData +{ + uint16_t stat; + int16_t x; + int16_t y; + string name; + string descr; + + void setup(); +}; + +void +InsertSubData::setup() +{ + MySQL::Connection &mysql = MySqlDB.conn(); + assert(mysql.connected()); + stringstream insert; + ccprintf(insert, + "INSERT INTO subdata(sd_stat,sd_x,sd_y,sd_name,sd_descr) " + "values(%d,%d,%d,\"%s\",\"%s\")", + stat, x, y, name, descr); + + mysql.query(insert); +// if (mysql.error) +// panic("could not insert subdata\n%s\n", mysql.error); + + if (mysql.commit()) + panic("could not commit transaction\n%s\n", mysql.error); +} + +void +InsertFormula(uint16_t stat, const string &formula) +{ + MySQL::Connection &mysql = MySqlDB.conn(); + assert(mysql.connected()); + stringstream insert_formula; + ccprintf(insert_formula, + "INSERT INTO formulas(fm_stat,fm_formula) values(%d, \"%s\")", + stat, formula); + + mysql.query(insert_formula); +// if (mysql.error) +// panic("could not insert formula\n%s\n", mysql.error); + + stringstream insert_ref; + ccprintf(insert_ref, + "INSERT INTO formula_ref(fr_stat,fr_run) values(%d, %d)", + stat, MySqlDB.run()); + + mysql.query(insert_ref); +// if (mysql.error) +// panic("could not insert formula reference\n%s\n", mysql.error); + + if (mysql.commit()) + panic("could not commit transaction\n%s\n", mysql.error); +} + +void +UpdatePrereq(uint16_t stat, uint16_t prereq) +{ + MySQL::Connection &mysql = MySqlDB.conn(); + assert(mysql.connected()); + stringstream update; + ccprintf(update, "UPDATE stats SET st_prereq=%d WHERE st_id=%d", + prereq, stat); + mysql.query(update); + if (mysql.error) + panic("could not update prereq\n%s\n", mysql.error); + + if (mysql.commit()) + panic("could not commit transaction\n%s\n", mysql.error); +} + +void +MySql::configure() +{ + /* + * set up all stats! + */ + using namespace Database; + + MySQL::Connection &mysql = MySqlDB.conn(); + + stat_list_t::const_iterator i, end = stats().end(); + for (i = stats().begin(); i != end; ++i) { + (*i)->visit(*this); + } + + for (i = stats().begin(); i != end; ++i) { + StatData *data = *i; + if (data->prereq) { + uint16_t stat_id = find(data->id); + uint16_t prereq_id = find(data->prereq->id); + assert(stat_id && prereq_id); + + UpdatePrereq(stat_id, prereq_id); + } + } + + if (mysql.commit()) + panic("could not commit transaction\n%s\n", mysql.error); + + configured = true; +} + + +bool +MySql::configure(const StatData &data, string type) +{ + stat.init(); + stat.name = data.name; + stat.descr = data.desc; + stat.type = type; + stat.print = data.flags & print; + stat.prec = data.precision; + stat.nozero = data.flags & nozero; + stat.nonan = data.flags & nonan; + stat.total = data.flags & total; + stat.pdf = data.flags & pdf; + stat.cdf = data.flags & cdf; + + return stat.print; +} + +void +MySql::configure(const ScalarData &data) +{ + if (!configure(data, "SCALAR")) + return; + + insert(data.id, stat.setup()); +} + +void +MySql::configure(const VectorData &data) +{ + if (!configure(data, "VECTOR")) + return; + + uint16_t statid = stat.setup(); + + if (!data.subnames.empty()) { + InsertSubData subdata; + subdata.stat = statid; + subdata.y = 0; + for (int i = 0; i < data.subnames.size(); ++i) { + subdata.x = i; + subdata.name = data.subnames[i]; + subdata.descr = data.subdescs.empty() ? "" : data.subdescs[i]; + + if (!subdata.name.empty() || !subdata.descr.empty()) + subdata.setup(); + } + } + + insert(data.id, statid); +} + +void +MySql::configure(const DistData &data) +{ + if (!configure(data, "DIST")) + return; + + if (!data.data.fancy) { + stat.size = data.data.size; + stat.min = data.data.min; + stat.max = data.data.max; + stat.bktsize = data.data.bucket_size; + } + insert(data.id, stat.setup()); +} + +void +MySql::configure(const VectorDistData &data) +{ + if (!configure(data, "VECTORDIST")) + return; + + if (!data.data[0].fancy) { + stat.size = data.data[0].size; + stat.min = data.data[0].min; + stat.max = data.data[0].max; + stat.bktsize = data.data[0].bucket_size; + } + + uint16_t statid = stat.setup(); + + if (!data.subnames.empty()) { + InsertSubData subdata; + subdata.stat = statid; + subdata.y = 0; + for (int i = 0; i < data.subnames.size(); ++i) { + subdata.x = i; + subdata.name = data.subnames[i]; + subdata.descr = data.subdescs.empty() ? "" : data.subdescs[i]; + if (!subdata.name.empty() || !subdata.descr.empty()) + subdata.setup(); + } + } + + insert(data.id, statid); +} + +void +MySql::configure(const Vector2dData &data) +{ + if (!configure(data, "VECTOR2D")) + return; + + uint16_t statid = stat.setup(); + + if (!data.subnames.empty()) { + InsertSubData subdata; + subdata.stat = statid; + subdata.y = -1; + for (int i = 0; i < data.subnames.size(); ++i) { + subdata.x = i; + subdata.name = data.subnames[i]; + subdata.descr = data.subdescs.empty() ? "" : data.subdescs[i]; + if (!subdata.name.empty() || !subdata.descr.empty()) + subdata.setup(); + } + } + + if (!data.y_subnames.empty()) { + InsertSubData subdata; + subdata.stat = statid; + subdata.x = -1; + subdata.descr = ""; + for (int i = 0; i < data.y_subnames.size(); ++i) { + subdata.y = i; + subdata.name = data.y_subnames[i]; + if (!subdata.name.empty()) + subdata.setup(); + } + } + + insert(data.id, statid); +} + +void +MySql::configure(const FormulaData &data) +{ + configure(data, "FORMULA"); + insert(data.id, stat.setup()); + InsertFormula(find(data.id), data.str()); +} + +bool +MySql::valid() const +{ + return MySqlDB.connected(); +} + +void +MySql::output() +{ + using namespace Database; + assert(valid()); + + if (!configured) + configure(); + + // store sample # + newdata.tick = curTick; + + MySQL::Connection &mysql = MySqlDB.conn(); + + Database::stat_list_t::const_iterator i, end = Database::stats().end(); + for (i = Database::stats().begin(); i != end; ++i) { + StatData *stat = *i; + stat->visit(*this); + if (mysql.commit()) + panic("could not commit transaction\n%s\n", mysql.error); + } + + newdata.flush(); +} + +void +MySql::output(const ScalarData &data) +{ + if (!(data.flags & print)) + return; + + newdata.stat = find(data.id); + newdata.x = 0; + newdata.y = 0; + newdata.data = data.value(); + + newdata.insert(); +} + +void +MySql::output(const VectorData &data) +{ + if (!(data.flags & print)) + return; + + newdata.stat = find(data.id); + newdata.y = 0; + + const VCounter &cvec = data.value(); + int size = data.size(); + for (int x = 0; x < size; x++) { + newdata.x = x; + newdata.data = cvec[x]; + newdata.insert(); + } +} + +void +MySql::output(const DistDataData &data) +{ + const int db_sum = -1; + const int db_squares = -2; + const int db_samples = -3; + const int db_min_val = -4; + const int db_max_val = -5; + const int db_underflow = -6; + const int db_overflow = -7; + + newdata.x = db_sum; + newdata.data = data.sum; + newdata.insert(); + + newdata.x = db_squares; + newdata.data = data.squares; + newdata.insert(); + + newdata.x = db_samples; + newdata.data = data.samples; + newdata.insert(); + + if (data.samples && !data.fancy) { + newdata.x = db_min_val; + newdata.data = data.min_val; + newdata.insert(); + + newdata.x = db_max_val; + newdata.data = data.max_val; + newdata.insert(); + + newdata.x = db_underflow; + newdata.data = data.underflow; + newdata.insert(); + + newdata.x = db_overflow; + newdata.data = data.overflow; + newdata.insert(); + + int size = data.cvec.size(); + for (int x = 0; x < size; x++) { + newdata.x = x; + newdata.data = data.cvec[x]; + newdata.insert(); + } + } +} + + +void +MySql::output(const DistData &data) +{ + if (!(data.flags & print)) + return; + + newdata.stat = find(data.id); + newdata.y = 0; + output(data.data); +} + +void +MySql::output(const VectorDistData &data) +{ + if (!(data.flags & print)) + return; + + newdata.stat = find(data.id); + + int size = data.data.size(); + for (int y = 0; y < size; ++y) { + newdata.y = y; + output(data.data[y]); + } +} + +void +MySql::output(const Vector2dData &data) +{ + if (!(data.flags & print)) + return; + + newdata.stat = find(data.id); + + int index = 0; + for (int x = 0; x < data.x; x++) { + newdata.x = x; + for (int y = 0; y < data.y; y++) { + newdata.y = y; + newdata.data = data.cvec[index++]; + newdata.insert(); + } + } +} + +void +MySql::output(const FormulaData &data) +{ +} + +/* + * Implement the visitor + */ +void +MySql::visit(const ScalarData &data) +{ + if (!configured) + configure(data); + else + output(data); +} + +void +MySql::visit(const VectorData &data) +{ + if (!configured) + configure(data); + else + output(data); +} + +void +MySql::visit(const DistData &data) +{ + return; + if (!configured) + configure(data); + else + output(data); +} + +void +MySql::visit(const VectorDistData &data) +{ + return; + if (!configured) + configure(data); + else + output(data); +} + +void +MySql::visit(const Vector2dData &data) +{ + return; + if (!configured) + configure(data); + else + output(data); +} + +void +MySql::visit(const FormulaData &data) +{ + if (!configured) + configure(data); + else + output(data); +} + +/* namespace Stats */ } |