📄 dbio.cc
字号:
// Copyright 2002 by Keith Vallerio.
// All rights reserved.
/************************************************************
dbio.cc
Twin file to database.cc. This file contains DB methods which
are needed for profiling, recompiling and generating a
task graph.
************************************************************/
#include "database.h"
#include "ArgPack.h"
#include <fstream>
#include <map>
#include <set>
#include <algorithm>
#include "ktime.h"
// Class used to temporarily store some annotation information
// from the start of a loop/cond or function call. This info
// is then recalled at the end of the loop/cond or func call.
class CallStackItem {
long tree_node_;
long source_fn_;
TimeUnit tu_;
public:
CallStackItem(long tn, long sf, TimeUnit t);
long tree_node() { return tree_node_; }
long source_fn() { return source_fn_; }
TimeUnit tu() { return tu_; }
};
// Constructor
CallStackItem::CallStackItem (long tn, long sf, TimeUnit t) :
tree_node_(tn), source_fn_(sf), tu_(t)
{
}
//------------------------------------------------------------
// Profile-related methods
//------------------------------------------------------------
// Recompiles source code. Uses "kmake.perl". This should be
// a user-modified script to call a make file or run gcc. Either
// way, the user should make sure that KSVtime.c is linked in with
// the new executable.
void DB::prof_recompile()
{
string fname = ArgPack::ap().get_fname();
string str = "kmake.perl " + fname;
cout << str << endl;
system (str.c_str());
// Don't use since some compilations can cause this to fail.
// It would be nice to assert that the compilation succeeded, but
// it must be done some other way...???
// Rassert (system (str.c_str()) == 0);
}
// Reruns executable. Removes old data so that it cannot be used
// to give bad results. Uses "krunner.perl". This should be a
// user-modified script to run the executable with appropriate
// input. This should be a trivial script, but is done this way
// to increase tool flexibility.
void DB::prof_rerun()
{
system ("rm KSV.out");
cout << "***Removing KSV.out***\n";
system ("krunner.perl");
// Don't use since some programs can cause this to fail.
// It would be nice to assert that this succeeded, but
// it must be done some other way...???
// Rassert (system ("a.out in1 in2") == 0);
}
// Read in data from rerunning new executable. Use the new info
// to generate edge and node weights for task graph.
void DB::prof_read_data()
{
ifstream annote_stream;
RVector<string> vec;
RVector<long> time_s;
RVector<long> time_us;
string s;
annote_stream.open("KSV.annote");
Rassert (annote_stream);
// First read data type sizes. "KSV" is the flag to indicate
// this is complete and the next section is starting.
do {
getline(annote_stream, s);
vec = tokenize (s);
Rassert(!vec.empty());
if (!(vec[0] == "KSV")) {
type_map_[vec[0]] = Conv(vec[1]);
}
} while (!(vec[0] == "KSV"));
// Read data profile times. Each line is read in as a
// tokenized string (with 5 components).
do {
getline(annote_stream, s);
vec = tokenize (s);
if (!vec.empty()) {
annote_data_.push_back(vec);
}
} while (! vec.empty());
/////////////////////////////////////////////////
// Use the profile data to get timing info
// -----------------------------------
// Each line has 5 parts:
// current_function
// event (func start/end, loop/cond start/end, statement_end
// AST tree node
// second -----\ These are the values from gettimeofday
// microsecond --/
/////////////////////////////////////////////////
// setup
TimeUnit t1, t2;
t1.set_time(0,0);
t2.set_time(0,0);
Rassert(annote_data_[0][1] == "fn_start");
// Analyze each line from the profile.
RVector<CallStackItem> fn_stack;
RVector<CallStackItem> loop_select_stack;
MAP (x, annote_data_.size()) {
// 'fn' is the function which the annotation is about
long fn = func_map(annote_data_[x][0]);
// 'fname' is the name of that function
string fname = function_[fn].name();
// Check function stack. The item on the top of the stack is
// the innermost function called. If 'fn' isn't in that
// function's call graph, then pop the stack. Repeat until
// the 'fn' is inside the current function's call graph.
// (Another reason to repeat poping is that 'fn' is a
// reinvocation of the current function. After popping
// a function, record how long that function took.
while (fn_stack.size()) {
// 'f' is the index of the current function
// 'new_f' is the same index as 'fn'
long fn_index = fn_stack.size() - 1;
long f = fn_stack[fn_index].source_fn();
long new_f = func_map(annote_data_[x][0]);
if (call_graph_.in_subtree(f, new_f)) {
break;
} else if (new_f == f) {
if (annote_data_[x][1] != "fn_start") {
break;
}
}
// If neither condition met, pop this item
t1 = fn_stack[fn_index].tu();
t2.set_time(Conv(annote_data_[x][3]), Conv(annote_data_[x][4]));
fg_[f].set_time_unit(t2-t1);
// cout << "FTIME: " << function_[f].name() << " " << t2-t1 << endl;
fn_stack.pop_back();
}
// Check loop/cond stack. The item on the top of the stack is
// the innermost loop/cond. If 'new_f' isn't in the current
// function's ('f') call graph, then pop the stack. Repeat until
// the 'f_new' is inside the current function's call graph.
// After popping a loop/cond, record how long it took.
while (loop_select_stack.size()) {
long loop_select_index = loop_select_stack.size() - 1;
long f = loop_select_stack[loop_select_index].source_fn();
long new_f = func_map(annote_data_[x][0]);
if (call_graph_.in_subtree(f, new_f)) {
break;
}
// If neither condition met, pop this item
t1 = loop_select_stack[loop_select_index].tu();
t2.set_time(Conv(annote_data_[x][3]), Conv(annote_data_[x][4]));
set_lc_task_time (
f, loop_select_stack[loop_select_index].tree_node(), t2-t1);
// cout << "LC: " << loop_select_stack[loop_select_index].tree_node()
// << " " << t2-t1 << endl;
loop_select_stack.pop_back();
}
// record how long a give line took
if (annote_data_[x][1] == "statement_end") {
t1.set_time(Conv(annote_data_[x-1][3]), Conv(annote_data_[x-1][4]));
t2.set_time(Conv(annote_data_[x][3]), Conv(annote_data_[x][4]));
set_se_task_time (fn, Conv(annote_data_[x][2]), t2-t1);
// cout << "SE: " << annote_data_[x][2] << " " << t2-t1 << endl;
} else if (annote_data_[x][1] == "fn_start") {
long tree_node = Conv(annote_data_[x][2]);
long f = func_map(annote_data_[x][0]);
Rassert(f != -1);
t1.set_time(Conv(annote_data_[x][3]), Conv(annote_data_[x][4]));
fn_stack.push_back(CallStackItem(tree_node, f, t1));
// Record preliminary info to later determine length of loop/cond
} else if ((annote_data_[x][1] == "loop_start") ||
(annote_data_[x][1] == "select_start")) {
long tree_node = Conv(annote_data_[x][2]);
long f = func_map(annote_data_[x][0]);
Rassert(f != -1);
t1.set_time(Conv(annote_data_[x][3]), Conv(annote_data_[x][4]));
loop_select_stack.push_back(CallStackItem(tree_node, f, t1));
}
}
set_all_fc_task_times ();
}
void DB::set_all_fc_task_times ()
{
Rassert(fg_.size() == function_.size());
MAP (x, function_.size()) {
RVector<long> func_node = fg_[x].func_call_nodes();
MAP (y, func_node.size()) {
TimeUnit tu;
tu.set_time(0,0);
RVector<long> call_list = fg_[x][func_node[y]].func();
MAP (z, call_list.size()) {
long fc_num = call_list[z];
TimeUnit t2 = fg_[fc_num].time_unit();
tu = tu + t2;
}
fg_[x][func_node[y]].set_time_unit(tu.sec(), tu.usec());
}
}
}
// set statement end node times
void DB::set_se_task_time (long f, long tree_node, TimeUnit t)
{
long n = fg_[f].find_se_node(tree_node);
Rassert(n != -1);
TimeUnit old_t = fg_[f][n].time_unit();
// keep worst-case time
if (old_t < t) {
fg_[f][n].set_time_unit(t.sec(), t.usec());
}
}
// set loop/cond node times
void DB::set_lc_task_time (long f, long tree_node, TimeUnit t)
{
long n = fg_[f].find_lc_node(tree_node);
Rassert(n != -1);
TimeUnit old_t = fg_[f][n].time_unit();
// keep worst-case time
if (old_t < t) {
fg_[f][n].set_time_unit(t.sec(), t.usec());
}
}
// Determine node edge sizes based on profile info.
void DB::prof_get_arc_lengths()
{
//--------------------------------------------------
// Determine sizes for each variable!!!
//--------------------------------------------------
MAP (x, variable_.size()) {
string type_name = variable_[x].type();
long type_size;
//cout << variable_[x].name() << " " << variable_[x].type();
// unknown variables' types are set equal to pointer size
if (type_map_.find(type_name) == type_map_.end()) {
type_size = ArgPack::ap().pointer_size();
} else {
type_size = type_map_[type_name];
}
variable_[x].determine_total_size(type_size);
// cout << " " << variable_[x].total_size() << endl;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -