traceflag stuff
[gem5.git] / src / base / stats / mysql.cc
1 /*
2 * Copyright (c) 2004-2005 The Regents of The University of Michigan
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met: redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer;
9 * redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution;
12 * neither the name of the copyright holders nor the names of its
13 * contributors may be used to endorse or promote products derived from
14 * this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 *
28 * Authors: Nathan Binkert
29 */
30
31 #include <cassert>
32 #include <map>
33 #include <sstream>
34 #include <string>
35 #include <vector>
36
37 #include "base/misc.hh"
38 #include "base/mysql.hh"
39 #include "base/statistics.hh"
40 #include "base/stats/flags.hh"
41 #include "base/stats/mysql.hh"
42 #include "base/stats/mysql_run.hh"
43 #include "base/stats/statdb.hh"
44 #include "base/stats/types.hh"
45 #include "base/str.hh"
46 #include "sim/host.hh"
47
48 using namespace std;
49
50 namespace Stats {
51
52 MySqlRun MySqlDB;
53
54 bool
55 MySqlConnected()
56 {
57 return MySqlDB.connected();
58 }
59
60 void
61 MySqlRun::connect(const string &host, const string &user, const string &passwd,
62 const string &db, const string &name, const string &sample,
63 const string &project)
64 {
65 if (connected())
66 panic("can only get one database connection at this time!");
67
68 mysql.connect(host, user, passwd, db);
69 if (mysql.error)
70 panic("could not connect to database server\n%s\n", mysql.error);
71
72 if (mysql.autocommit(false))
73 panic("could not set autocommit\n%s\n", mysql.error);
74
75 remove(name);
76 //cleanup();
77 setup(name, sample, user, project);
78 }
79
80 void
81 MySqlRun::setup(const string &name, const string &sample, const string &user,
82 const string &project)
83 {
84 assert(mysql.connected());
85
86 stringstream insert;
87 ccprintf(insert,
88 "INSERT INTO "
89 "runs(rn_name,rn_sample,rn_user,rn_project,rn_date,rn_expire)"
90 "values(\"%s\", \"%s\", \"%s\", \"%s\", NOW(),"
91 "DATE_ADD(CURDATE(), INTERVAL 31 DAY))",
92 name, sample, user, project);
93
94 mysql.query(insert);
95 if (mysql.error)
96 panic("could not get a run\n%s\n", mysql.error);
97
98 run_id = mysql.insert_id();
99 if (mysql.commit())
100 panic("could not commit transaction\n%s\n", mysql.error);
101 }
102
103 void
104 MySqlRun::remove(const string &name)
105 {
106 assert(mysql.connected());
107 stringstream sql;
108 ccprintf(sql, "DELETE FROM runs WHERE rn_name=\"%s\"", name);
109 mysql.query(sql);
110 if (mysql.error)
111 panic("could not delete run\n%s\n", mysql.error);
112 if (mysql.commit())
113 panic("could not commit transaction\n%s\n", mysql.error);
114 }
115
116 void
117 MySqlRun::cleanup()
118 {
119 assert(mysql.connected());
120
121 mysql.query("DELETE data "
122 "FROM data "
123 "LEFT JOIN runs ON dt_run=rn_id "
124 "WHERE rn_id IS NULL");
125
126 if (mysql.commit())
127 panic("could not commit transaction\n%s\n", mysql.error);
128
129 mysql.query("DELETE formula_ref "
130 "FROM formula_ref "
131 "LEFT JOIN runs ON fr_run=rn_id "
132 "WHERE rn_id IS NULL");
133
134 if (mysql.commit())
135 panic("could not commit transaction\n%s\n", mysql.error);
136
137 mysql.query("DELETE formulas "
138 "FROM formulas "
139 "LEFT JOIN formula_ref ON fm_stat=fr_stat "
140 "WHERE fr_stat IS NULL");
141
142 if (mysql.commit())
143 panic("could not commit transaction\n%s\n", mysql.error);
144
145 mysql.query("DELETE stats "
146 "FROM stats "
147 "LEFT JOIN data ON st_id=dt_stat "
148 "WHERE dt_stat IS NULL");
149
150 if (mysql.commit())
151 panic("could not commit transaction\n%s\n", mysql.error);
152
153 mysql.query("DELETE subdata "
154 "FROM subdata "
155 "LEFT JOIN data ON sd_stat=dt_stat "
156 "WHERE dt_stat IS NULL");
157
158 if (mysql.commit())
159 panic("could not commit transaction\n%s\n", mysql.error);
160
161 mysql.query("DELETE events"
162 "FROM events"
163 "LEFT JOIN runs ON ev_run=rn_id"
164 "WHERE rn_id IS NULL");
165
166 if (mysql.commit())
167 panic("could not commit transaction\n%s\n", mysql.error);
168
169 mysql.query("DELETE event_names"
170 "FROM event_names"
171 "LEFT JOIN events ON en_id=ev_event"
172 "WHERE ev_event IS NULL");
173
174 if (mysql.commit())
175 panic("could not commit transaction\n%s\n", mysql.error);
176 }
177
178 void
179 SetupStat::init()
180 {
181 name = "";
182 descr = "";
183 type = "";
184 print = false;
185 prereq = 0;
186 prec = -1;
187 nozero = false;
188 nonan = false;
189 total = false;
190 pdf = false;
191 cdf = false;
192 min = 0;
193 max = 0;
194 bktsize = 0;
195 size = 0;
196 }
197
198 unsigned
199 SetupStat::setup()
200 {
201 MySQL::Connection &mysql = MySqlDB.conn();
202
203 stringstream insert;
204 ccprintf(insert,
205 "INSERT INTO "
206 "stats(st_name, st_descr, st_type, st_print, st_prereq, "
207 "st_prec, st_nozero, st_nonan, st_total, st_pdf, st_cdf, "
208 "st_min, st_max, st_bktsize, st_size)"
209 "values(\"%s\",\"%s\",\"%s\","
210 " %d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d)",
211 name, descr, type, print, prereq, (int)prec, nozero, nonan,
212 total, pdf, cdf,
213 min, max, bktsize, size);
214
215 mysql.query(insert);
216 if (!mysql.error) {
217 int id = mysql.insert_id();
218 if (mysql.commit())
219 panic("could not commit transaction\n%s\n", mysql.error);
220 return id;
221 }
222
223 stringstream select;
224 ccprintf(select, "SELECT * FROM stats WHERE st_name=\"%s\"", name);
225
226 mysql.query(select);
227 MySQL::Result result = mysql.store_result();
228 if (!result)
229 panic("could not find stat\n%s\n", mysql.error);
230
231 assert(result.num_fields() == 16);
232 MySQL::Row row = result.fetch_row();
233 if (!row)
234 panic("could not get stat row\n%s\n", mysql.error);
235
236 bool tb;
237 int8_t ti8;
238 uint16_t tu16;
239 int64_t ti64;
240 uint64_t tu64;
241
242 if (name != (char *)row[1])
243 panic("failed stat check on %s:name. %s != %s\n",
244 name, name, row[1]);
245
246 if (descr != (char *)row[2])
247 panic("failed stat check on %s:descr. %s != %s\n",
248 name, descr, row[2]);
249
250 if (type != (char *)row[3])
251 panic("failed stat check on %s:type. %s != %s\n",
252 name, type, row[3]);
253
254 if (!to_number(row[4], tb) || print != tb)
255 panic("failed stat check on %s:print. %d != %d\n",
256 name, print, tb);
257
258 if (!to_number(row[6], ti8) || prec != ti8)
259 panic("failed stat check on %s:prec. %d != %d\n",
260 name, prec, ti8);
261
262 if (!to_number(row[7], tb) || nozero != tb)
263 panic("failed stat check on %s:nozero. %d != %d\n",
264 name, nozero, tb);
265
266 if (!to_number(row[8], tb) || nonan != tb)
267 panic("failed stat check on %s:nonan. %d != %d\n",
268 name, nonan, tb);
269
270 if (!to_number(row[9], tb) || total != tb)
271 panic("failed stat check on %s:total. %d != %d\n",
272 name, total, tb);
273
274 if (!to_number(row[10], tb) || pdf != tb)
275 panic("failed stat check on %s:pdf. %d != %d\n",
276 name, pdf, tb);
277
278 if (!to_number(row[11], tb) || cdf != tb)
279 panic("failed stat check on %s:cdf. %d != %d\n",
280 name, cdf, tb);
281
282 if (!to_number(row[12], ti64) || min != ti64)
283 panic("failed stat check on %s:min. %d != %d\n",
284 name, min, ti64);
285
286 if (!to_number(row[13], ti64) || max != ti64)
287 panic("failed stat check on %s:max. %d != %d\n",
288 name, max, ti64);
289
290 if (!to_number(row[14], tu64) || bktsize != tu64)
291 panic("failed stat check on %s:bktsize. %d != %d\n",
292 name, bktsize, tu64);
293
294 if (!to_number(row[15], tu16) || size != tu16)
295 panic("failed stat check on %s:size. %d != %d\n",
296 name, size, tu16);
297
298 to_number(row[5], prereq);
299 uint16_t statid;
300 to_number(row[0], statid);
301 return statid;
302 }
303
304 InsertData::InsertData()
305 {
306 query = new char[maxsize + 1];
307 size = 0;
308 flush();
309 }
310
311 InsertData::~InsertData()
312 {
313 delete [] query;
314 }
315
316 void
317 InsertData::flush()
318 {
319 if (size) {
320 MySQL::Connection &mysql = MySqlDB.conn();
321 assert(mysql.connected());
322 mysql.query(query);
323 if (mysql.error)
324 panic("could not insert data\n%s\n", mysql.error);
325 if (mysql.commit())
326 panic("could not commit transaction\n%s\n", mysql.error);
327 }
328
329 query[0] = '\0';
330 size = 0;
331 first = true;
332 strcpy(query, "INSERT INTO "
333 "data(dt_stat,dt_x,dt_y,dt_run,dt_tick,dt_data) "
334 "values");
335 size = strlen(query);
336 }
337
338 void
339 InsertData::insert()
340 {
341 if (size + 1024 > maxsize)
342 flush();
343
344 if (!first) {
345 query[size++] = ',';
346 query[size] = '\0';
347 }
348
349 first = false;
350
351 size += sprintf(query + size, "(%u,%d,%d,%u,%llu,\"%f\")",
352 stat, x, y, MySqlDB.run(), (unsigned long long)tick,
353 data);
354 }
355
356 struct InsertSubData
357 {
358 uint16_t stat;
359 int16_t x;
360 int16_t y;
361 string name;
362 string descr;
363
364 void setup();
365 };
366
367 void
368 InsertSubData::setup()
369 {
370 MySQL::Connection &mysql = MySqlDB.conn();
371 assert(mysql.connected());
372 stringstream insert;
373 ccprintf(insert,
374 "INSERT INTO subdata(sd_stat,sd_x,sd_y,sd_name,sd_descr) "
375 "values(%d,%d,%d,\"%s\",\"%s\")",
376 stat, x, y, name, descr);
377
378 mysql.query(insert);
379 // if (mysql.error)
380 // panic("could not insert subdata\n%s\n", mysql.error);
381
382 if (mysql.commit())
383 panic("could not commit transaction\n%s\n", mysql.error);
384 }
385
386 void
387 InsertFormula(uint16_t stat, const string &formula)
388 {
389 MySQL::Connection &mysql = MySqlDB.conn();
390 assert(mysql.connected());
391 stringstream insert_formula;
392 ccprintf(insert_formula,
393 "INSERT INTO formulas(fm_stat,fm_formula) values(%d, \"%s\")",
394 stat, formula);
395
396 mysql.query(insert_formula);
397 // if (mysql.error)
398 // panic("could not insert formula\n%s\n", mysql.error);
399
400 stringstream insert_ref;
401 ccprintf(insert_ref,
402 "INSERT INTO formula_ref(fr_stat,fr_run) values(%d, %d)",
403 stat, MySqlDB.run());
404
405 mysql.query(insert_ref);
406 // if (mysql.error)
407 // panic("could not insert formula reference\n%s\n", mysql.error);
408
409 if (mysql.commit())
410 panic("could not commit transaction\n%s\n", mysql.error);
411 }
412
413 void
414 UpdatePrereq(uint16_t stat, uint16_t prereq)
415 {
416 MySQL::Connection &mysql = MySqlDB.conn();
417 assert(mysql.connected());
418 stringstream update;
419 ccprintf(update, "UPDATE stats SET st_prereq=%d WHERE st_id=%d",
420 prereq, stat);
421 mysql.query(update);
422 if (mysql.error)
423 panic("could not update prereq\n%s\n", mysql.error);
424
425 if (mysql.commit())
426 panic("could not commit transaction\n%s\n", mysql.error);
427 }
428
429 void
430 MySql::configure()
431 {
432 /*
433 * set up all stats!
434 */
435 using namespace Database;
436
437 MySQL::Connection &mysql = MySqlDB.conn();
438
439 stat_list_t::const_iterator i, end = stats().end();
440 for (i = stats().begin(); i != end; ++i) {
441 (*i)->visit(*this);
442 }
443
444 for (i = stats().begin(); i != end; ++i) {
445 StatData *data = *i;
446 if (data->prereq) {
447 uint16_t stat_id = find(data->id);
448 uint16_t prereq_id = find(data->prereq->id);
449 assert(stat_id && prereq_id);
450
451 UpdatePrereq(stat_id, prereq_id);
452 }
453 }
454
455 if (mysql.commit())
456 panic("could not commit transaction\n%s\n", mysql.error);
457
458 configured = true;
459 }
460
461
462 bool
463 MySql::configure(const StatData &data, string type)
464 {
465 stat.init();
466 stat.name = data.name;
467 stat.descr = data.desc;
468 stat.type = type;
469 stat.print = data.flags & print;
470 stat.prec = data.precision;
471 stat.nozero = data.flags & nozero;
472 stat.nonan = data.flags & nonan;
473 stat.total = data.flags & total;
474 stat.pdf = data.flags & pdf;
475 stat.cdf = data.flags & cdf;
476
477 return stat.print;
478 }
479
480 void
481 MySql::configure(const ScalarData &data)
482 {
483 if (!configure(data, "SCALAR"))
484 return;
485
486 insert(data.id, stat.setup());
487 }
488
489 void
490 MySql::configure(const VectorData &data)
491 {
492 if (!configure(data, "VECTOR"))
493 return;
494
495 uint16_t statid = stat.setup();
496
497 if (!data.subnames.empty()) {
498 InsertSubData subdata;
499 subdata.stat = statid;
500 subdata.y = 0;
501 for (int i = 0; i < data.subnames.size(); ++i) {
502 subdata.x = i;
503 subdata.name = data.subnames[i];
504 subdata.descr = data.subdescs.empty() ? "" : data.subdescs[i];
505
506 if (!subdata.name.empty() || !subdata.descr.empty())
507 subdata.setup();
508 }
509 }
510
511 insert(data.id, statid);
512 }
513
514 void
515 MySql::configure(const DistData &data)
516 {
517 if (!configure(data, "DIST"))
518 return;
519
520 if (!data.data.fancy) {
521 stat.size = data.data.size;
522 stat.min = data.data.min;
523 stat.max = data.data.max;
524 stat.bktsize = data.data.bucket_size;
525 }
526 insert(data.id, stat.setup());
527 }
528
529 void
530 MySql::configure(const VectorDistData &data)
531 {
532 if (!configure(data, "VECTORDIST"))
533 return;
534
535 if (!data.data[0].fancy) {
536 stat.size = data.data[0].size;
537 stat.min = data.data[0].min;
538 stat.max = data.data[0].max;
539 stat.bktsize = data.data[0].bucket_size;
540 }
541
542 uint16_t statid = stat.setup();
543
544 if (!data.subnames.empty()) {
545 InsertSubData subdata;
546 subdata.stat = statid;
547 subdata.y = 0;
548 for (int i = 0; i < data.subnames.size(); ++i) {
549 subdata.x = i;
550 subdata.name = data.subnames[i];
551 subdata.descr = data.subdescs.empty() ? "" : data.subdescs[i];
552 if (!subdata.name.empty() || !subdata.descr.empty())
553 subdata.setup();
554 }
555 }
556
557 insert(data.id, statid);
558 }
559
560 void
561 MySql::configure(const Vector2dData &data)
562 {
563 if (!configure(data, "VECTOR2D"))
564 return;
565
566 uint16_t statid = stat.setup();
567
568 if (!data.subnames.empty()) {
569 InsertSubData subdata;
570 subdata.stat = statid;
571 subdata.y = -1;
572 for (int i = 0; i < data.subnames.size(); ++i) {
573 subdata.x = i;
574 subdata.name = data.subnames[i];
575 subdata.descr = data.subdescs.empty() ? "" : data.subdescs[i];
576 if (!subdata.name.empty() || !subdata.descr.empty())
577 subdata.setup();
578 }
579 }
580
581 if (!data.y_subnames.empty()) {
582 InsertSubData subdata;
583 subdata.stat = statid;
584 subdata.x = -1;
585 subdata.descr = "";
586 for (int i = 0; i < data.y_subnames.size(); ++i) {
587 subdata.y = i;
588 subdata.name = data.y_subnames[i];
589 if (!subdata.name.empty())
590 subdata.setup();
591 }
592 }
593
594 insert(data.id, statid);
595 }
596
597 void
598 MySql::configure(const FormulaData &data)
599 {
600 configure(data, "FORMULA");
601 insert(data.id, stat.setup());
602 InsertFormula(find(data.id), data.str());
603 }
604
605 bool
606 MySql::valid() const
607 {
608 return MySqlDB.connected();
609 }
610
611 void
612 MySql::output()
613 {
614 using namespace Database;
615 assert(valid());
616
617 if (!configured)
618 configure();
619
620 // store sample #
621 newdata.tick = curTick;
622
623 MySQL::Connection &mysql = MySqlDB.conn();
624
625 Database::stat_list_t::const_iterator i, end = Database::stats().end();
626 for (i = Database::stats().begin(); i != end; ++i) {
627 StatData *stat = *i;
628 stat->visit(*this);
629 if (mysql.commit())
630 panic("could not commit transaction\n%s\n", mysql.error);
631 }
632
633 newdata.flush();
634 }
635
636 void
637 MySql::output(const ScalarData &data)
638 {
639 if (!(data.flags & print))
640 return;
641
642 newdata.stat = find(data.id);
643 newdata.x = 0;
644 newdata.y = 0;
645 newdata.data = data.value();
646
647 newdata.insert();
648 }
649
650 void
651 MySql::output(const VectorData &data)
652 {
653 if (!(data.flags & print))
654 return;
655
656 newdata.stat = find(data.id);
657 newdata.y = 0;
658
659 const VCounter &cvec = data.value();
660 int size = data.size();
661 for (int x = 0; x < size; x++) {
662 newdata.x = x;
663 newdata.data = cvec[x];
664 newdata.insert();
665 }
666 }
667
668 void
669 MySql::output(const DistDataData &data)
670 {
671 const int db_sum = -1;
672 const int db_squares = -2;
673 const int db_samples = -3;
674 const int db_min_val = -4;
675 const int db_max_val = -5;
676 const int db_underflow = -6;
677 const int db_overflow = -7;
678
679 newdata.x = db_sum;
680 newdata.data = data.sum;
681 newdata.insert();
682
683 newdata.x = db_squares;
684 newdata.data = data.squares;
685 newdata.insert();
686
687 newdata.x = db_samples;
688 newdata.data = data.samples;
689 newdata.insert();
690
691 if (data.samples && !data.fancy) {
692 newdata.x = db_min_val;
693 newdata.data = data.min_val;
694 newdata.insert();
695
696 newdata.x = db_max_val;
697 newdata.data = data.max_val;
698 newdata.insert();
699
700 newdata.x = db_underflow;
701 newdata.data = data.underflow;
702 newdata.insert();
703
704 newdata.x = db_overflow;
705 newdata.data = data.overflow;
706 newdata.insert();
707
708 int size = data.cvec.size();
709 for (int x = 0; x < size; x++) {
710 newdata.x = x;
711 newdata.data = data.cvec[x];
712 newdata.insert();
713 }
714 }
715 }
716
717
718 void
719 MySql::output(const DistData &data)
720 {
721 if (!(data.flags & print))
722 return;
723
724 newdata.stat = find(data.id);
725 newdata.y = 0;
726 output(data.data);
727 }
728
729 void
730 MySql::output(const VectorDistData &data)
731 {
732 if (!(data.flags & print))
733 return;
734
735 newdata.stat = find(data.id);
736
737 int size = data.data.size();
738 for (int y = 0; y < size; ++y) {
739 newdata.y = y;
740 output(data.data[y]);
741 }
742 }
743
744 void
745 MySql::output(const Vector2dData &data)
746 {
747 if (!(data.flags & print))
748 return;
749
750 newdata.stat = find(data.id);
751
752 int index = 0;
753 for (int x = 0; x < data.x; x++) {
754 newdata.x = x;
755 for (int y = 0; y < data.y; y++) {
756 newdata.y = y;
757 newdata.data = data.cvec[index++];
758 newdata.insert();
759 }
760 }
761 }
762
763 void
764 MySql::output(const FormulaData &data)
765 {
766 }
767
768 /*
769 * Implement the visitor
770 */
771 void
772 MySql::visit(const ScalarData &data)
773 {
774 if (!configured)
775 configure(data);
776 else
777 output(data);
778 }
779
780 void
781 MySql::visit(const VectorData &data)
782 {
783 if (!configured)
784 configure(data);
785 else
786 output(data);
787 }
788
789 void
790 MySql::visit(const DistData &data)
791 {
792 return;
793 if (!configured)
794 configure(data);
795 else
796 output(data);
797 }
798
799 void
800 MySql::visit(const VectorDistData &data)
801 {
802 return;
803 if (!configured)
804 configure(data);
805 else
806 output(data);
807 }
808
809 void
810 MySql::visit(const Vector2dData &data)
811 {
812 return;
813 if (!configured)
814 configure(data);
815 else
816 output(data);
817 }
818
819 void
820 MySql::visit(const FormulaData &data)
821 {
822 if (!configured)
823 configure(data);
824 else
825 output(data);
826 }
827
828 /* namespace Stats */ }