-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmain.cpp
More file actions
219 lines (187 loc) · 8.37 KB
/
Copy pathmain.cpp
File metadata and controls
219 lines (187 loc) · 8.37 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
#include <iostream>
#include <string>
#include <filesystem>
#include <mpi.h>
#include "data_loader.h"
#include "analytics.h"
#include "omp_engine.h"
#include "mpi_engine.h"
#include "hybrid_engine.h"
#include "performance.h"
#include "report_generator.h"
#include "result_io.h"
/**
* Entry point: Parallel Financial Analytics Engine
*
* Two execution modes are supported:
*
* Separate-run mode (recommended; engines run independently without contention):
* ./MCP_final <csv_path> seq [max_rows] # Sequential only
* ./MCP_final <csv_path> omp [max_rows] [omp_threads] # OpenMP only
* mpirun -np 4 ./MCP_final <csv_path> mpi [max_rows] # MPI only
* mpirun -np 4 ./MCP_final <csv_path> hybrid [max_rows] [omp_threads] # MPI + OpenMP
* ./MCP_final report # Merge results and generate report
*
* Combined mode (all engines in one invocation; backward-compatible):
* ./MCP_final <csv_path> all [max_rows] [omp_threads]
* mpirun -np 4 ./MCP_final <csv_path> all [max_rows] [omp_threads]
*
* Each separate-run mode saves results to a .result file under results/.
* The report mode reads those files and produces a combined performance
* comparison report and report.html.
*/
static void print_usage(const char* prog) {
std::cerr << "Usage:\n"
<< " " << prog << " <csv_path> seq [max_rows] [threads] [sample_ratio]\n"
<< " " << prog << " <csv_path> omp [max_rows] [threads] [sample_ratio]\n"
<< " mpirun -np N " << prog << " <csv_path> mpi [max_rows] [threads] [sample_ratio]\n"
<< " mpirun -np N " << prog << " <csv_path> hybrid [max_rows] [threads] [sample_ratio]\n"
<< " " << prog << " <csv_path> all [max_rows] [threads] [sample_ratio]\n"
<< " " << prog << " report\n"
<< "\n"
<< " sample_ratio: 0.0~1.0, e.g. 0.5 = random 50% (default 1.0 = use all)\n";
}
int main(int argc, char* argv[]) {
MPI_Init(&argc, &argv);
int mpi_rank = 0, mpi_size = 1;
MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank);
MPI_Comm_size(MPI_COMM_WORLD, &mpi_size);
if (argc < 2) {
if (mpi_rank == 0) print_usage(argv[0]);
MPI_Finalize();
return 1;
}
std::string arg1 = argv[1];
/* ── report mode: merge existing result files and generate report ── */
if (arg1 == "report") {
if (mpi_rank == 0) {
std::vector<RunStats> stats;
std::string results_dir = "results";
// Load in fixed order: seq → omp → mpi → hybrid.
std::string files[] = {
results_dir + "/seq.result",
results_dir + "/omp.result",
results_dir + "/mpi.result",
results_dir + "/hybrid.result"
};
for (const auto& f : files) {
if (std::filesystem::exists(f)) {
stats.push_back(load_run_stats(f));
std::cout << "[Report] Loaded " << f << "\n";
}
}
if (stats.empty()) {
std::cerr << "[Report] No result files found in results/ directory.\n";
MPI_Finalize();
return 1;
}
print_performance_report(stats);
// The original csv_path is not stored in seq.result; use a placeholder.
generate_html_report("report.html", stats, "(merged from separate runs)");
}
MPI_Finalize();
return 0;
}
/* ── All other modes require csv_path and mode ───────────────── */
if (argc < 3) {
if (mpi_rank == 0) print_usage(argv[0]);
MPI_Finalize();
return 1;
}
std::string csv_path = argv[1];
std::string mode = argv[2];
size_t max_rows = (argc >= 4) ? std::stoull(argv[3]) : 0;
int omp_threads = (argc >= 5) ? std::stoi(argv[4]) : 0;
double sample_ratio = (argc >= 6) ? std::stod(argv[5]) : 1.0;
// Create results directory if it does not exist.
if (mpi_rank == 0) {
std::filesystem::create_directories("results");
}
bool run_seq = (mode == "seq" || mode == "all");
bool run_omp = (mode == "omp" || mode == "all");
bool run_mpi = (mode == "mpi" || mode == "all");
bool run_hybrid = (mode == "hybrid" || mode == "all");
/* ── Load data on rank 0 (with optional random sampling) ────── */
std::vector<Transaction> records;
if (mpi_rank == 0) {
DataLoader loader(csv_path);
records = loader.load(max_rows);
if (sample_ratio > 0.0 && sample_ratio < 1.0) {
records = DataLoader::sample(records, sample_ratio);
}
}
std::vector<RunStats> stats;
/* ── Sequential ───────────────────────────────────────────────── */
if (run_seq && mpi_rank == 0) {
Timer t;
auto result = Analytics::run_sequential(records);
double ms = t.elapsed_ms();
RunStats s = {"Sequential", ms, 1, result};
stats.push_back(s);
save_run_stats("results/seq.result", s);
std::cout << "\n[Sequential]\n";
print_analytics_summary(result);
}
/* ── OpenMP ───────────────────────────────────────────────────── */
if (run_omp && mpi_rank == 0) {
OmpEngine omp(omp_threads);
Timer t;
auto result = omp.run(records);
double ms = t.elapsed_ms();
RunStats s = {"OpenMP-" + std::to_string(omp.num_threads()),
ms, omp.num_threads(), result};
stats.push_back(s);
save_run_stats("results/omp.result", s);
std::cout << "\n[OpenMP – " << omp.num_threads() << " threads]\n";
print_analytics_summary(result);
}
/* ── MPI ──────────────────────────────────────────────────────── */
if (run_mpi) {
MpiEngine mpi_engine;
MPI_Barrier(MPI_COMM_WORLD);
Timer t;
auto result = mpi_engine.run(records);
double ms = t.elapsed_ms();
if (mpi_rank == 0) {
RunStats s = {"MPI-" + std::to_string(mpi_engine.world_size()),
ms, mpi_engine.world_size(), result};
stats.push_back(s);
save_run_stats("results/mpi.result", s);
std::cout << "\n[MPI – " << mpi_engine.world_size() << " ranks]\n";
print_analytics_summary(result);
}
}
/* ── Hybrid MPI + OpenMP ─────────────────────────────────────── */
if (run_hybrid) {
HybridEngine hybrid(omp_threads);
MPI_Barrier(MPI_COMM_WORLD);
Timer t;
auto result = hybrid.run(records);
double ms = t.elapsed_ms();
if (mpi_rank == 0) {
const int total_workers = hybrid.world_size() * hybrid.omp_threads();
RunStats s = {"Hybrid-MPI-" + std::to_string(hybrid.world_size()) +
"xOMP-" + std::to_string(hybrid.omp_threads()),
ms, total_workers, result};
stats.push_back(s);
save_run_stats("results/hybrid.result", s);
std::cout << "\n[Hybrid – " << hybrid.world_size() << " MPI ranks × "
<< hybrid.omp_threads() << " OpenMP threads]\n";
print_analytics_summary(result);
}
}
/* ── Output report ───────────────────────────────────────────── */
if (mpi_rank == 0 && !stats.empty()) {
// In "all" mode generate the full report immediately.
if (mode == "all") {
print_performance_report(stats);
generate_html_report("report.html", stats, csv_path);
} else {
// In separate-run mode remind the user to run the report step.
std::cout << "\n[Hint] Run '" << argv[0]
<< " report' to merge all results and generate report.html\n";
}
}
MPI_Finalize();
return 0;
}