Program Listing for File profiler.cpp
↰ Return to documentation for file (lib/profiler.cpp
)
#include "AnalysisGraph.hpp"
#include <tqdm.hpp>
#include "utils.hpp"
#include "Timer.hpp"
#include "CSVWriter.hpp"
#ifdef _OPENMP
#include <omp.h>
#endif
#include <future>
using namespace std;
using tq::trange;
void AnalysisGraph::initialize_profiler(int res,
int kde_kernels,
InitialBeta initial_beta,
InitialDerivative initial_derivative,
bool use_continuous) {
unordered_set<int> train_vertices =
unordered_set<int>
(this->node_indices().begin(), this->node_indices().end());
this->concept_sample_pool.clear();
for (int vert : train_vertices) {
if (this->head_nodes.find(vert) == this->head_nodes.end()) {
this->concept_sample_pool.push_back(vert);
}
}
this->edge_sample_pool.clear();
for (EdgeDescriptor ed : this->edges()) {
if (!this->graph[ed].is_frozen()) {
this->edge_sample_pool.push_back(ed);
}
}
this->n_kde_kernels = kde_kernels;
this->initialize_parameters(res, initial_beta, initial_derivative,
false, use_continuous);
}
void AnalysisGraph::profile_mcmc(int run, string file_name_prefix) {
this->n_timesteps = this->observed_state_sequence.size();
int n_nodes = this->num_nodes();
int n_edges = this->num_edges();
pair<std::vector<std::string>, std::vector<long>> durations;
string filename = file_name_prefix + "_" +
to_string(n_nodes) + "-" +
to_string(n_edges) + "_" +
to_string(run) + "_" +
delphi::utils::get_timestamp() + ".csv";
CSVWriter writer(filename);
vector<string> headings = {"Run", "Nodes", "Edges", "KDE Kernels", "Wall Clock Time (ns)", "CPU Time (ns)", "Sample Type"};
writer.write_row(headings.begin(), headings.end());
cout << filename << endl;
cout << "\nProfiling the MCMC\n";
cout << "\nSampling " << this->res << " samples from posterior..." << endl;
for (int i : trange(this->res)) {
{
durations.first.clear();
durations.second.clear();
durations.first = {"Run", "Nodes", "Edges", "KDE Kernels"};
durations.second = {run,n_nodes, n_edges, long(this->n_kde_kernels)};
Timer t = Timer("MCMC", durations);
this->sample_from_posterior();
}
durations.first.push_back("Sample Type");
durations.second.push_back(this->coin_flip < this->coin_flip_thresh ? 1
: 0);
writer.write_row(durations.second.begin(), durations.second.end());
this->transition_matrix_collection[i] = this->A_original;
this->initial_latent_state_collection[i] = this->s0;
}
cout << endl;
this->trained = true;
RNG::release_instance();
}
void AnalysisGraph::profile_kde(int run, string file_name_prefix) {
this->initialize_random_number_generator();
int n_nodes = this->num_nodes();
int n_edges = this->num_edges();
pair<std::vector<std::string>, std::vector<long>> durations_kde;
pair<std::vector<std::string>, std::vector<long>> durations_me;
pair<std::vector<std::string>, std::vector<long>> durations_uptm;
string filename = file_name_prefix + "_" +
to_string(n_nodes) + "-" +
to_string(n_edges) + "_" +
to_string(run) + "_" +
delphi::utils::get_timestamp() + ".csv";
CSVWriter writer(filename);
vector<string> headings = {"Run", "Nodes", "Edges", "KDE Kernels", "Wall Clock Time (ns)", "CPU Time (ns)", "Sample Type"};
writer.write_row(headings.begin(), headings.end());
cout << filename << endl;
int num_iterations = int(this->res / 2);
cout << "\nProfiling the KDE\n";
cout << "\nRunning KDE for " << num_iterations << " times..." << endl;
for (int i : trange(num_iterations)) {
// Randomly pick an edge ≡ θ
boost::iterator_range edge_it = this->edges();
vector<EdgeDescriptor> e(1);
sample(
edge_it.begin(), edge_it.end(), e.begin(), 1, this->rand_num_generator);
// Perturb the θ
this->graph[e[0]].set_theta(this->graph[e[0]].get_theta() + this->norm_dist(this->rand_num_generator));
KDE& kde = this->graph[e[0]].kde;
{
durations_uptm.first.clear();
durations_uptm.second.clear();
durations_uptm.first = {"Run", "Nodes", "Edges", "KDE Kernels"};
durations_uptm.second = {run,n_nodes, n_edges, long(this->n_kde_kernels)};
Timer t = Timer("UPTM", durations_uptm);
this->update_transition_matrix_cells(e[0]);
}
durations_uptm.first.push_back("Sample Type");
durations_uptm.second.push_back(12);
writer.write_row(durations_uptm.second.begin(), durations_uptm.second.end());
{
durations_kde.first.clear();
durations_kde.second.clear();
durations_kde.first = {"Run", "Nodes", "Edges", "KDE Kernels"};
durations_kde.second = {run,n_nodes, n_edges, long(this->n_kde_kernels)};
Timer t = Timer("KDE", durations_kde);
this->graph[e[0]].compute_logpdf_theta();
}
durations_kde.first.push_back("Sample Type");
durations_kde.second.push_back(10);
writer.write_row(durations_kde.second.begin(), durations_kde.second.end());
{
durations_me.first.clear();
durations_me.second.clear();
durations_me.first = {"Run", "Nodes", "Edges", "KDE Kernels"};
durations_me.second = {run,n_nodes, n_edges, long(this->n_kde_kernels)};
Timer t = Timer("ME", durations_me);
#ifdef _OPENMP
this->e_A_ts.clear();
#pragma omp parallel
{
unordered_map<double, Eigen::MatrixXd> partial_e_A_ts;
for (int i = 0; i < this->observation_timestep_unique_gaps.size();
i++) {
int gap = this->observation_timestep_unique_gaps[i];
partial_e_A_ts[gap] = (this->A_original * gap).exp();
}
#pragma omp critical
this->e_A_ts.merge(partial_e_A_ts);
#pragma omp barrier
}
#else
for (auto [gap, mat] : this->e_A_ts) {
this->e_A_ts[gap] = (this->A_original * gap).exp();
}
#endif
}
durations_me.first.push_back("Sample Type");
durations_me.second.push_back(11);
writer.write_row(durations_me.second.begin(), durations_me.second.end());
}
cout << endl;
RNG::release_instance();
}
void AnalysisGraph::profile_prediction(int run, int pred_timesteps, string file_name_prefix) {
if (!this->trained) {
cout << "\n\n\t****ERROR: Untrained model! Cannot generate projections...\n\n";
return;
}
int n_nodes = this->num_nodes();
int n_edges = this->num_edges();
pair<std::vector<std::string>, std::vector<long>> durations;
string filename = file_name_prefix + "_" +
to_string(n_nodes) + "-" +
to_string(n_edges) + "_" +
to_string(run) + "_" +
delphi::utils::get_timestamp() + ".csv";
CSVWriter writer(filename);
vector<string> headings = {"Run", "Nodes", "Edges", "Timesteps", "Wall Clock Time (ns)", "CPU Time (ns)"};
writer.write_row(headings.begin(), headings.end());
cout << filename << endl;
cout << "\nProfiling prediction\n";
cout << "\nRunning prediction for " << pred_timesteps + 1 << " times..." << endl;
{
durations.first.clear();
durations.second.clear();
durations.first = {"Run", "Nodes", "Edges", "Timesteps"};
durations.second = {run,n_nodes, n_edges, pred_timesteps + 1};
Timer t = Timer("Prediction", durations);
this->generate_prediction(1, pred_timesteps);
}
writer.write_row(durations.second.begin(), durations.second.end());
cout << endl;
}
mutex g_display_mutex;
static Eigen::MatrixXd compute_matrix_exponential(const Eigen::Ref<const Eigen::MatrixXd> A, double gap) {
thread::id this_id = std::this_thread::get_id();
g_display_mutex.lock();
cout << "\nthread: " << this_id << endl;
g_display_mutex.unlock();
return (A * gap).exp();
}
void AnalysisGraph::profile_matrix_exponential(int run, std::string file_name_prefix,
std::vector<double> unique_gaps,
int repeat,
bool multi_threaded) {
this->initialize_random_number_generator();
int n_nodes = this->num_nodes();
int n_edges = this->num_edges();
pair<std::vector<std::string>, std::vector<long>> durations_me;
string filename = file_name_prefix +
(multi_threaded ? "mt_" : "st_") +
to_string(n_nodes) + "-" +
to_string(n_edges) + "_" +
to_string(run) + "_" +
delphi::utils::get_timestamp() + ".csv";
CSVWriter writer(filename);
vector<string> headings = {"Run", "Nodes", "Edges",
"KDE Kernels", "Wall Clock Time (ns)",
"CPU Time (ns)", "Sample Type"};
writer.write_row(headings.begin(), headings.end());
cout << filename << endl;
vector<future<Eigen::MatrixXd>> matrix_exponentials(unique_gaps.size());
if (multi_threaded) {
thread::id this_id = std::this_thread::get_id();
cout << "\nmain thread: " << this_id << endl;
cout << "\nmax hardware threads: " << thread::hardware_concurrency() << endl;
}
this->observation_timestep_unique_gaps = unique_gaps;
this->res = repeat;
cout << "\nProfiling Matrix Exponential\n";
cout << "\nRunning Matrix Exponential for " << this->res << " times..." << endl;
for (int i : trange(this->res)) {
// Randomly pick an edge ≡ θ
boost::iterator_range edge_it = this->edges();
vector<EdgeDescriptor> e(1);
sample(
edge_it.begin(), edge_it.end(), e.begin(), 1, this->rand_num_generator);
// Perturb the θ
this->graph[e[0]].set_theta(this->graph[e[0]].get_theta() +
this->norm_dist(this->rand_num_generator) / 10);
KDE& kde = this->graph[e[0]].kde;
this->update_transition_matrix_cells(e[0]);
this->graph[e[0]].compute_logpdf_theta();
durations_me.first.clear();
durations_me.second.clear();
durations_me.first = {"Run", "Nodes", "Edges", "KDE Kernels"};
durations_me.second = {run,n_nodes, n_edges, long(this->n_kde_kernels)};
{
Timer t = Timer("ME", durations_me);
if (multi_threaded) {
/*
this->e_A_ts.clear();
#pragma omp parallel
{
unordered_map<double, Eigen::MatrixXd> partial_e_A_ts;
for (int i = 0;
i < this->observation_timestep_unique_gaps.size();
i++) {
int gap = this->observation_timestep_unique_gaps[i];
partial_e_A_ts[gap] = (this->A_original * gap).exp();
}
#pragma omp critical
//dumb++;
this->e_A_ts.merge(partial_e_A_ts);
#pragma omp barrier
}
*/
for (int i = 0;
i < this->observation_timestep_unique_gaps.size();
i++) {
int gap = this->observation_timestep_unique_gaps[i];
matrix_exponentials[i] = async(launch::async,// | launch::deferred,
compute_matrix_exponential,
A_original, gap);
}
for (int i = 0;
i < this->observation_timestep_unique_gaps.size();
i++) {
int gap = this->observation_timestep_unique_gaps[i];
this->e_A_ts[gap] = matrix_exponentials[i].get();
}
}
else {
for (double gap : this->observation_timestep_unique_gaps) {
this->e_A_ts[gap] = (this->A_original * gap).exp();
}
}
}
/*
for (double gap :unique_gaps) {
cout << "\ngap: " << gap << endl;
cout << this->e_A_ts[gap] << endl;
}
*/
durations_me.first.push_back("Sample Type");
durations_me.second.push_back(multi_threaded ? 13
: 11);
writer.write_row(durations_me.second.begin(), durations_me.second.end());
}
cout << endl;
RNG::release_instance();
cout << "\nmax hardware threads: " << thread::hardware_concurrency() << endl;
}