mageec  0.1.0
MAchine Guided Energy Efficient Compilation
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
database.cpp
Go to the documentation of this file.
1 /* MAGEEC Machine Learner Datbase
2  Copyright (C) 2013, 2014 Embecosm Limited and University of Bristol
3 
4  This file is part of MAGEEC.
5 
6  This program is free software: you can redistribute it and/or modify
7  it under the terms of the GNU General Public License as published by
8  the Free Software Foundation, either version 3 of the License, or
9  (at your option) any later version.
10 
11  This program is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  GNU General Public License for more details.
15 
16  You should have received a copy of the GNU General Public License
17  along with this program. If not, see <http://www.gnu.org/licenses/>. */
18 
20 #include "mageec/mageec-ml.h"
21 #include "mageec/mageec.h"
22 #include <cassert>
23 
24 using namespace mageec;
25 
31 database::database(std::string dbname, bool create)
32 {
33  int loaded;
34  if (create)
35  loaded = sqlite3_open (dbname.c_str(), &db);
36  else
37  loaded = sqlite3_open_v2 (dbname.c_str(), &db, SQLITE_OPEN_READONLY, NULL);
38 
39  // If we could not open the database, we can not use machine learning
40  assert(loaded == 0 && "Unable to load machine learning database.");
41 
42  /* Enable foreign keys (requires sqlite 3.6.19 or above)
43  (If foreign keys are not available, the database will perform, but no
44  foreign key checking will be done) */
45  sqlite3_exec(db, "PRAGMA foreign_keys = ON", NULL, NULL, NULL);
46 
47  if (create)
48  initdb();
49 }
50 
52 {
53  if (db)
54  sqlite3_close (db);
55 }
56 
62 {
63  if (!db)
64  return 1;
65 
66  int retval;
67 
68  // Pass list table
69  char qinit[] = "CREATE TABLE IF NOT EXISTS passes (passname TEXT PRIMARY KEY)";
70  retval = sqlite3_exec(db, qinit, NULL, NULL, NULL);
71 
72  // Pass (executed) order table
73  char qinit2[] = "CREATE TABLE IF NOT EXISTS passorder (seq INTEGER NOT NULL, "
74  "pos INTEGER NOT NULL, pass TEXT NOT NULL, "
75  "PRIMARY KEY (seq, pos))";
76  retval |= sqlite3_exec(db, qinit2, NULL, NULL, NULL);
77 
78  char qinit3[] = "CREATE TABLE IF NOT EXISTS features (prog TEXT NOT NULL, "
79  "feature INTEGER NOT NULL, value INTEGER NOT NULL, "
80  "PRIMARY KEY (prog, feature))";
81  retval |= sqlite3_exec(db, qinit3, NULL, NULL, NULL);
82 
83  // Program result table
84  char qinit4[] = "CREATE TABLE IF NOT EXISTS results (prog TEXT NOT NULL, "
85  "seq INTEGER NOT NULL, time INTEGER, energy INTEGER, "
86  "PRIMARY KEY (prog, seq))";
87  retval |= sqlite3_exec(db, qinit4, NULL, NULL, NULL);
88 
89  // Pass blob table (for e.g. storing tree output)
90  char qinit5[] = "CREATE TABLE IF NOT EXISTS passblob (pass TEXT, blob TEXT, "
91  "PRIMARY KEY (pass))";
92  retval |= sqlite3_exec(db, qinit5, NULL, NULL, NULL);
93 
94  return retval;
95 }
96 
101 std::vector<mageec_pass*> database::get_pass_list()
102 {
103  std::vector<mageec_pass*> passes;
104  if (!db)
105  return passes;
106 
107  sqlite3_stmt *stmt;
108  char query[] = "SELECT * FROM passes";
109  int retval = sqlite3_prepare_v2 (db, query, -1, &stmt, 0);
110  if (retval)
111  return passes;
112 
113  /* The current design of the database we always use the first column. Should
114  this change in the future, this function should also be changed. */
115  while (1)
116  {
117  retval = sqlite3_step(stmt);
118  if(retval == SQLITE_ROW)
119  {
120  const char *val = reinterpret_cast<const char *>(sqlite3_column_text(stmt,0));
121  passes.push_back(new basic_pass(val));
122  }
123  else if (retval == SQLITE_DONE)
124  break;
125  }
126  return passes;
127 }
128 
134 {
135  char *buffer;
136  sqlite3_stmt *stmt;
137 
138  // Calcualte hash
139  std::string hashdata;
140  for (unsigned long i=0, size=res.passlist.size(); i < size; i++)
141  hashdata += res.passlist[i]->name();
142  uint64_t hash = hash_data (hashdata.c_str(), hashdata.size());
143 
144  /* For SQLite we can only store signed numbers, therefore we sign transform,
145  allowing any sorting to still work */
146  int64_t shash = static_cast<int64_t>(hash) ^
147  static_cast<int64_t>(0x8000000000000000);
148 
149  // Check if hash already exists
150  buffer = sqlite3_mprintf ("SELECT seq FROM passorder WHERE seq = %lli "
151  "GROUP BY seq", shash);
152  if (!buffer)
153  return;
154  int retval = sqlite3_prepare_v2 (db, buffer, -1, &stmt, 0);
155  sqlite3_free (buffer);
156  if (retval)
157  return;
158 
159  // FIXME: Add collision detection
160  retval = sqlite3_step(stmt);
161  if (retval != SQLITE_DONE)
162  {
163  // The hash search has not found any result, add passes to database
164  for (unsigned long i=0, size=res.passlist.size(); i < size; i++)
165  {
166  buffer = sqlite3_mprintf ("INSERT INTO passorder VALUES (%lli, %i, %Q)",
167  shash, i,
168  res.passlist[i]->name().c_str());
169  if (!buffer)
170  return;
171  sqlite3_exec (db, buffer, NULL, NULL, NULL);
172  sqlite3_free (buffer);
173  }
174  }
175 
176  // Add result
177  buffer = sqlite3_mprintf ("INSERT INTO results VALUES (%Q, %lli, 0, %i)",
178  res.progname.c_str(), shash,
179  res.metric);
180  if (!buffer)
181  return;
182  sqlite3_exec (db, buffer, NULL, NULL, NULL);
183  sqlite3_free (buffer);
184 }
185 
186 std::vector<result> database::get_all_results()
187 {
188  std::vector<result> results;
189  char *buffer;
190  int retval, passretval;
191  sqlite3_stmt *stmt, *passstmt;
192 
193  // FIXME: Make the minimal request a parameter. Perhaps another function?
194  buffer = sqlite3_mprintf("SELECT `PROG`, `SEQ`, MIN(`energy`) FROM (SELECT "
195  "`rowid`,* FROM `results` ORDER BY `rowid` ASC "
196  "LIMIT 0, 50000) GROUP BY `PROG`");
197  retval = sqlite3_prepare_v2 (db, buffer, -1, &stmt, 0);
198  sqlite3_free (buffer);
199  if (retval)
200  return results;
201 
202  while (1)
203  {
204  retval = sqlite3_step(stmt);
205  if (retval == SQLITE_ROW)
206  {
207  const char *progkey = reinterpret_cast<const char *>(sqlite3_column_text(stmt, 0));
208  const char *passkey = reinterpret_cast<const char *>(sqlite3_column_text(stmt, 1));
209 
210  // Select pass list for test
211  std::vector<mageec_pass *> passes;
212  buffer = sqlite3_mprintf ("SELECT * FROM passorder WHERE seq = %s ORDER "
213  "BY pos", passkey);
214  passretval = sqlite3_prepare_v2 (db, buffer, -1, &passstmt, 0);
215  sqlite3_free (buffer);
216  if (passretval)
217  continue;
218  while (1)
219  {
220  passretval = sqlite3_step(passstmt);
221  if (passretval == SQLITE_ROW)
222  {
223  const char *passname = reinterpret_cast<const char *>(sqlite3_column_text(passstmt, 2));
224  passes.push_back (new basic_pass(passname));
225  }
226  else if (passretval == SQLITE_DONE)
227  break;
228  }
229 
230  // Select feature set for test
231  std::vector<mageec_feature *> features;
232  buffer = sqlite3_mprintf ("SELECT * FROM features WHERE prog = %Q ORDER "
233  "BY feature", progkey);
234  passretval = sqlite3_prepare_v2 (db, buffer, -1, &passstmt, 0);
235  sqlite3_free (buffer);
236  if (passretval)
237  continue;
238  while (1)
239  {
240  passretval = sqlite3_step(passstmt);
241  if (passretval == SQLITE_ROW)
242  {
243  const char *featname = reinterpret_cast<const char *>(sqlite3_column_text(passstmt, 1));
244  int featdata = sqlite3_column_int(passstmt, 2);
245  features.push_back (new basic_feature(featname, featdata));
246  }
247  else if (passretval == SQLITE_DONE)
248  break;
249  }
250 
251  // Build object and add to results
252  int energy = sqlite3_column_int(stmt, 3);
253  result res;
254  res.passlist = passes;
255  res.featlist = features;
256  res.progname = progkey;
257  res.metric = energy;
258  results.push_back (res);
259  }
260  else if (retval == SQLITE_DONE)
261  break;
262  }
263 
264  return results;
265 }
266 
267 void database::store_pass_blob(std::string passname, char *blob)
268 {
269  char *buffer;
270  buffer = sqlite3_mprintf ("DELETE FROM passblob WHERE pass = %Q",
271  passname.c_str());
272  sqlite3_exec (db, buffer, NULL, NULL, NULL);
273  sqlite3_free (buffer);
274 
275  buffer = sqlite3_mprintf ("INSERT INTO passblob VALUES (%Q, %Q)",
276  passname.c_str(),
277  blob);
278  sqlite3_exec (db, buffer, NULL, NULL, NULL);
279  sqlite3_free (buffer);
280 }
281 
282 const char *database::get_pass_blob(std::string passname)
283 {
284  char *buffer;
285  int retval;
286  sqlite3_stmt *stmt;
287  buffer = sqlite3_mprintf("SELECT blob FROM passblob WHERE pass = %Q",
288  passname.c_str());
289  retval = sqlite3_prepare_v2(db, buffer, -1, &stmt, 0);
290  sqlite3_free(buffer);
291 
292  // Return code is non-zero if selection failed
293  if (retval)
294  return NULL;
295 
296  retval = sqlite3_step(stmt);
297  if (retval == SQLITE_ROW)
298  {
299  const char *data = reinterpret_cast<const char *>(sqlite3_column_text(stmt, 0));
300  return data;
301  }
302 
303  return NULL;
304 }