// Accumulate data from children into their parent. void LocalState::TrieNode::propagate_data_upwards (void) { for (auto citer = children.begin(); citer != children.end(); citer++) { TrieNode* child = citer->second; child->propagate_data_upwards(); for (size_t i = 0; i < self_data.size(); i++) path_data[i] += child->path_data[i]; invocations += child->invocations; } }
// Construct various tables in preparation for output. void LocalState::finalize (void) { // Find the line-number column. lineno_col = nullptr; for (auto citer = table_data.begin(); citer != table_data.end(); citer++) { Column* column = *citer; string colname(column->name); if (colname == "Line number" || colname == "Leaf line number") lineno_col = column; } if (lineno_col == nullptr) cerr << progname << ": Failed to find a \"Line number\" or \"Leaf line number\" column in the \"Functions\" table_data\n" << die; if (lineno_col->type != Column::UINT64_T) cerr << progname << ": The \"" << lineno_col->name << "\" column does not contain integer data\n" << die; // Find the invocation-count column. invoke_col = nullptr; for (auto citer = table_data.begin(); citer != table_data.end(); citer++) { Column* column = *citer; string colname(column->name); if (colname == "Invocations") invoke_col = column; } if (invoke_col == nullptr) cerr << progname << ": Failed to find an \"Invocations\" column in the \"Functions\" table_data\n" << die; if (invoke_col->type != Column::UINT64_T) cerr << progname << ": The \"" << invoke_col->name << "\" column does not contain integer data\n" << die; // Construct a mapping from file name to ID and back. size_t id = 1; file_col = nullptr; for (size_t i = 0; i < table_data.size(); i++) if (table_data[i]->name == "File name" || table_data[i]->name == "Leaf file name") { file_col = table_data[i]; break; } if (file_col == nullptr) cerr << progname << ": Failed to find a \"File name\" or \"Leaf file name\" column in the \"Functions\" table_data\n" << die; if (file_col->type != Column::STRING_T) cerr << progname << ": The \"" << file_col->name << "\" column does not contain string data\n" << die; for (auto riter = file_col->string_data->begin(); riter != file_col->string_data->end(); riter++) { string fname = *riter; if (fname2id.find(fname) != fname2id.end()) continue; fname2id[fname] = id; id2fname[id] = fname; id++; } // Construct a mapping from demangled function name or demangled call stack // to ID and back. id = 1; func_col = nullptr; for (size_t i = 0; i < table_data.size(); i++) if (table_data[i]->name == "Demangled function name" || table_data[i]->name == "Demangled call stack") { func_col = table_data[i]; break; } if (func_col == nullptr) cerr << progname << ": Failed to find a \"Demangled function name\" or \"Demangled call stack\" column in the \"Functions\" table\n" << die; if (func_col->type != Column::STRING_T) cerr << progname << ": The \"" << func_col->name << "\" column does not contain string data\n" << die; size_t row = 0; for (auto riter = func_col->string_data->begin(); riter != func_col->string_data->end(); riter++, row++) { string func = *riter; string func_only(func.substr(0, func.find(" # "))); if (func2id.find(func_only) != func2id.end()) continue; func2id[func_only] = id; id2func[id] = func_only; funcid2fnameid[id] = fname2id[(*file_col->string_data)[row]]; id++; } // Insert each call path into a trie forest. Compute inclusive and exclude // metrics. size_t func_col_num = func_col->number; size_t nrows = func_col->string_data->size(); call_forest = new LocalState::TrieNode(this); for (size_t r = 0; r < nrows; r++) call_forest->insert(func_col_num, r); auto citer = call_forest->children.begin(); if (citer != call_forest->children.end()) { // Initialize the root to have all-zero data. TrieNode* child = citer->second; call_forest->self_data.resize(child->self_data.size(), 0); call_forest->path_data.resize(child->path_data.size(), 0); } call_forest->propagate_data_upwards(); }