-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmain.cpp
More file actions
143 lines (118 loc) · 5.13 KB
/
Copy pathmain.cpp
File metadata and controls
143 lines (118 loc) · 5.13 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
#include "CandidatePropagator.hpp"
#include "Netlist.hpp"
#include "Partitioner.hpp"
#include "TopologyGraph.hpp"
#include <cstdlib>
#include <iomanip>
#include <iostream>
#include <sstream>
/*
README
======
Compile:
cmake -S . -B build
cmake --build build -j
Run:
./build/TopoPartitioner <topo_file> <netlist_file> <r_parameter> <num_threads> <seed>
Example:
./build/TopoPartitioner "ICCAD2021-Benchmarks/FPGA Graph/MFS1" \
"ICCAD2021-Benchmarks/Generated Benchmarks/case1" 0.05 8 2026
Verify:
The program prints cut cost, partition sizes, topology violations, fixed
violations, and speedup. A valid topology-constrained result has zero topology
violations, zero fixed violations, and every partition size within the printed
lower/upper bounds. When r * N == 1, partition sizes differ by at most one.
*/
namespace {
void print_usage(const char* argv0) {
std::cerr << "Usage:\n"
<< " " << argv0
<< " <topo_file> <netlist_file> <r_parameter> <num_threads> <seed>\n";
}
double parse_double(const char* value, const std::string& name) {
char* end = nullptr;
const double parsed = std::strtod(value, &end);
require_or_throw(end != value && *end == '\0', "Invalid " + name + ": " + value);
return parsed;
}
int parse_int(const char* value, const std::string& name) {
char* end = nullptr;
const long parsed = std::strtol(value, &end, 10);
require_or_throw(end != value && *end == '\0', "Invalid " + name + ": " + value);
require_or_throw(parsed > 0 && parsed <= std::numeric_limits<int>::max(),
name + " must be a positive integer");
return static_cast<int>(parsed);
}
std::uint64_t parse_u64(const char* value, const std::string& name) {
char* end = nullptr;
const unsigned long long parsed = std::strtoull(value, &end, 10);
require_or_throw(end != value && *end == '\0', "Invalid " + name + ": " + value);
return static_cast<std::uint64_t>(parsed);
}
void print_sizes(const std::vector<int>& sizes) {
std::cout << "Partition Size Distribution:";
for (std::size_t i = 0; i < sizes.size(); ++i) {
std::cout << (i == 0 ? " " : ", ") << i << ":" << sizes[i];
}
std::cout << '\n';
}
} // namespace
int main(int argc, char** argv) {
if (argc != 6) {
print_usage(argv[0]);
return 1;
}
try {
const std::string topo_path = argv[1];
const std::string netlist_path = argv[2];
const double r = parse_double(argv[3], "r_parameter");
const int threads = parse_int(argv[4], "num_threads");
const std::uint64_t seed = parse_u64(argv[5], "seed");
const long long load_start = now_microseconds();
TopologyGraph topology;
topology.load_from_file(topo_path);
Netlist netlist;
netlist.load_from_file(netlist_path, topology.num_nodes());
CandidateMask candidates = CandidatePropagator::initialize_and_propagate(netlist, topology);
const double load_seconds = static_cast<double>(now_microseconds() - load_start) / 1'000'000.0;
PartitionConfig config;
config.balance_ratio = r;
config.num_threads = threads;
config.seed = seed;
config.max_passes = 20;
Partitioner partitioner(topology, netlist, candidates);
const BalanceLimits limits = partitioner.compute_balance_limits(r);
double single_seconds = 0.0;
double multi_seconds = 0.0;
double speedup = 0.0;
PartitionResult result = partitioner.run_parallel(config, single_seconds, multi_seconds, speedup);
std::cout << std::fixed << std::setprecision(6);
std::cout << "Topology Nodes: " << topology.num_nodes() << '\n';
std::cout << "Netlist Nodes: " << netlist.num_nodes() << '\n';
std::cout << "Netlist Edges: " << netlist.num_edges() << '\n';
std::cout << "Balance Lower Bound: " << limits.lower << '\n';
std::cout << "Balance Upper Bound: " << limits.upper << '\n';
std::cout << "Total Cut Cost: " << result.cut_cost << '\n';
print_sizes(result.part_sizes);
std::cout << "Number of Topology Violations: " << result.topology_violations << '\n';
std::cout << "Number of Fixed Constraint Violations: " << result.fixed_violations << '\n';
std::cout << "Input and CPP Time Seconds: " << load_seconds << '\n';
// Speedup compares equal work: `threads` independent attempts run
// sequentially vs. the same count run in parallel (best-of-N search).
std::cout << "Attempts Per Batch: " << threads << '\n';
std::cout << "Single-thread Time Seconds: " << single_seconds << '\n';
std::cout << "Multi-thread Time Seconds: " << multi_seconds << '\n';
std::cout << "Parallel Speedup Ratio: " << speedup << '\n';
std::cout << "Feasible: " << (result.feasible ? "yes" : "no") << '\n';
if (!result.feasible) {
if (!result.message.empty()) {
std::cerr << "[ERROR] " << result.message << '\n';
}
return 2;
}
} catch (const std::exception& e) {
std::cerr << "[ERROR] " << e.what() << '\n';
return 1;
}
return 0;
}