Skip to content

Commit 0ff796e

Browse files
lums658claude
andcommitted
Refactor APB benchmarks: rename to abstraction_penalty and modularize
- Rename bench/apb/ to bench/abstraction_penalty/ - Create apb_common.hpp with shared infrastructure: - bench() function template to eliminate timing boilerplate - Args struct for consistent CLI parsing - load_graph() function for graph loading - Refactor all 8 APB benchmark files to use shared infrastructure - Remove ~1100 lines of duplicated code - Add descriptive file headers documenting what each benchmark measures - Remove dead code (#if 0 blocks, unused variables) - Fix containers.cpp VOV format support Line count improvements: - bfs.cpp: 419 -> 261 (38% reduction) - dfs.cpp: 277 -> 170 (39% reduction) - spmv.cpp: 444 -> 180 (59% reduction) - plain.cpp: 596 -> 296 (50% reduction) - dijkstra.cpp: 384 -> 187 (51% reduction) - exec.cpp: 222 -> 121 (45% reduction) - tbb.cpp: 359 -> 176 (51% reduction) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent 4233e23 commit 0ff796e

File tree

20 files changed

+1812
-2913
lines changed

20 files changed

+1812
-2913
lines changed

agents/nwgraph_instructions.md

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ This document tracks cleanup tasks for the NWGraph codebase, including completed
3333
### Apply Consistent Code Formatting
3434
- [x] Run clang-format on all 88 headers in `include/nwgraph/`
3535
- [x] Run clang-format on all test files in `test/`
36-
- [x] Run clang-format on all benchmark files in `bench/` (gapbs and apb)
36+
- [x] Run clang-format on all benchmark files in `bench/` (gapbs and abstraction_penalty)
3737
- [x] Run clang-format on all example files in `examples/`
3838

3939
**Formatting standards (defined in `.clang-format`):**
@@ -169,9 +169,9 @@ Known TODO locations:
169169
- [x] Move all benchmarks under `bench/` with subdirectories:
170170
```
171171
bench/
172-
├── gapbs/ # NWGraph GAP Benchmark Suite implementations
173-
├── apb/ # Abstraction Penalty Benchmarks
174-
└── gapbs-reference/ # Original GAP Benchmark Suite (submodule)
172+
├── gapbs/ # NWGraph GAP Benchmark Suite implementations
173+
├── abstraction_penalty/ # Abstraction Penalty Benchmarks
174+
└── gapbs-reference/ # Original GAP Benchmark Suite (submodule)
175175
```
176176
- [x] Update `CMakeLists.txt` to reflect new directory structure
177177
- [x] Add original GAP Benchmark Suite as submodule for comparison
@@ -187,12 +187,26 @@ Known TODO locations:
187187
- `tc.cpp` converted to use `Times` class and `Log.hpp`
188188
- `js.cpp` disabled (commented out, needs conversion if re-enabled)
189189

190-
### Abstraction Penalty Benchmarks (`bench/apb/`)
191-
- [x] Move current `apb/` contents to `bench/apb/`
190+
### Abstraction Penalty Benchmarks (`bench/abstraction_penalty/`)
191+
- [x] Move current `apb/` contents to `bench/abstraction_penalty/`
192192
- [x] Connect APB executables to `bench` target
193-
- [ ] Bring APB benchmarks to same quality level as GAP benchmarks (future)
193+
- [x] Create shared infrastructure (`apb_common.hpp`):
194+
- `bench()` function template to eliminate timing boilerplate
195+
- `Args` struct for consistent CLI parsing
196+
- `load_graph()` function for graph loading
197+
- [x] Refactor all APB benchmarks to use shared infrastructure:
198+
- `bfs.cpp` - BFS traversal benchmarks (261 lines, was 419)
199+
- `dfs.cpp` - DFS traversal benchmarks (170 lines, was 277)
200+
- `spmv.cpp` - SpMV benchmarks (180 lines, was 444)
201+
- `plain.cpp` - Plain range benchmarks (296 lines, was 596)
202+
- `dijkstra.cpp` - Dijkstra property access (188 lines, was 384)
203+
- `exec.cpp` - Execution policy benchmarks (121 lines, was 222)
204+
- `tbb.cpp` - TBB parallelization benchmarks (176 lines, was 359)
205+
- `containers.cpp` - Container comparison benchmarks (235 lines)
206+
- [x] Remove dead code (`#if 0` blocks, unused variables)
207+
- [x] Add descriptive file headers documenting what each benchmark measures
194208
- [ ] Ensure consistent logging and output format (future)
195-
- [ ] Document what each APB measures (iteration overhead, container overhead, etc.) (future)
209+
- [ ] Add structured output matching gapbs pattern (future)
196210

197211
### Build Options
198212
- `NWGRAPH_BUILD_BENCH=ON` - Build NWGraph benchmarks (gapbs + apb)

bench/CMakeLists.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
# This directory contains benchmark implementations organized into subdirectories:
55
#
66
# gapbs/ - NWGraph implementations of GAP Benchmark Suite
7-
# apb/ - Abstraction Penalty Benchmarks
7+
# abstraction_penalty/ - Abstraction Penalty Benchmarks
88
# gapbs-reference/ - Original GAP Benchmark Suite (submodule, optional)
99
# =============================================================================
1010

@@ -15,7 +15,7 @@ add_custom_target(bench)
1515
# Include subdirectories
1616
# -----------------------------------------------------------------------------
1717
add_subdirectory(gapbs)
18-
add_subdirectory(apb)
18+
add_subdirectory(abstraction_penalty)
1919

2020
# -----------------------------------------------------------------------------
2121
# Original GAP Benchmark Suite (optional, for comparison)
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,3 +53,10 @@ add_dependencies(bench dijkstra.exe)
5353
add_executable(dfs.exe dfs.cpp)
5454
target_link_libraries(dfs.exe nwgraph)
5555
add_dependencies(bench dfs.exe)
56+
57+
# -----------------------------------------------------------------------------
58+
# Container abstraction penalty (requires docopt)
59+
# -----------------------------------------------------------------------------
60+
add_executable(containers.exe containers.cpp)
61+
target_link_libraries(containers.exe nwgraph docopt)
62+
add_dependencies(bench containers.exe)
Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
/**
2+
* @file apb_common.hpp
3+
*
4+
* @brief Common utilities for abstraction penalty benchmarks.
5+
*
6+
* @copyright SPDX-FileCopyrightText: 2022 Battelle Memorial Institute
7+
* @copyright SPDX-FileCopyrightText: 2022 University of Washington
8+
*
9+
* SPDX-License-Identifier: BSD-3-Clause
10+
*
11+
* @authors
12+
* Andrew Lumsdaine
13+
*
14+
*/
15+
16+
#ifndef NW_GRAPH_APB_COMMON_HPP
17+
#define NW_GRAPH_APB_COMMON_HPP
18+
19+
#include <fstream>
20+
#include <iostream>
21+
#include <string>
22+
#include <utility>
23+
24+
#include "nwgraph/edge_list.hpp"
25+
#include "nwgraph/io/mmio.hpp"
26+
#include "nwgraph/util/timer.hpp"
27+
28+
namespace nw::graph::apb {
29+
30+
/**
31+
* @brief Run a benchmark with setup and timed work phases.
32+
*
33+
* @tparam Setup Callable for per-trial setup (not timed)
34+
* @tparam Work Callable for timed work
35+
* @param name Benchmark name for output
36+
* @param ntrial Number of trials to run
37+
* @param setup Setup function called before each trial (not timed)
38+
* @param work Work function to time
39+
* @return Average time per trial in milliseconds
40+
*/
41+
template <typename Setup, typename Work>
42+
double bench(const std::string& name, size_t ntrial, Setup&& setup, Work&& work) {
43+
double time = 0;
44+
nw::util::ms_timer t(name);
45+
for (size_t i = 0; i < ntrial; ++i) {
46+
setup();
47+
t.start();
48+
work();
49+
t.stop();
50+
time += t.elapsed();
51+
}
52+
std::cout << t.name() << " " << time / ntrial << " ms" << std::endl;
53+
return time / ntrial;
54+
}
55+
56+
/**
57+
* @brief Run a benchmark without setup phase.
58+
*
59+
* @tparam Work Callable for timed work
60+
* @param name Benchmark name for output
61+
* @param ntrial Number of trials to run
62+
* @param work Work function to time
63+
* @return Average time per trial in milliseconds
64+
*/
65+
template <typename Work>
66+
double bench(const std::string& name, size_t ntrial, Work&& work) {
67+
return bench(name, ntrial, [] {}, std::forward<Work>(work));
68+
}
69+
70+
/**
71+
* @brief Load a graph from file (Matrix Market or serialized BGL17 format).
72+
*
73+
* @tparam Directedness Graph directedness (directed or undirected)
74+
* @tparam Attributes Edge attribute types
75+
* @param file Path to graph file
76+
* @return edge_list containing the graph
77+
*/
78+
template <nw::graph::directedness Directedness, class... Attributes>
79+
nw::graph::edge_list<Directedness, Attributes...> load_graph(const std::string& file) {
80+
std::ifstream in(file);
81+
std::string type;
82+
in >> type;
83+
84+
if (type == "BGL17") {
85+
nw::util::life_timer _(std::string("deserialize ") + file);
86+
nw::graph::edge_list<Directedness, Attributes...> el(0);
87+
el.deserialize(file);
88+
return el;
89+
} else if (type == "%%MatrixMarket") {
90+
nw::util::life_timer _(std::string("read_mm ") + file);
91+
return nw::graph::read_mm<Directedness, Attributes...>(file);
92+
} else {
93+
std::cerr << "Error: Unrecognized graph file format: " << file << "\n";
94+
std::cerr << "Expected 'BGL17' or '%%MatrixMarket' header\n";
95+
exit(1);
96+
}
97+
}
98+
99+
/**
100+
* @brief Print usage message and exit.
101+
*
102+
* @param prog Program name (argv[0])
103+
* @param msg Optional additional message
104+
*/
105+
inline void usage(const std::string& prog, const std::string& msg = "") {
106+
if (!msg.empty()) {
107+
std::cerr << "Error: " << msg << "\n";
108+
}
109+
std::cerr << "Usage: " << prog << " -f FILE [-n NTRIALS] [-v] [-d]\n";
110+
std::cerr << " -f, --file FILE Input graph file (Matrix Market or BGL17)\n";
111+
std::cerr << " -n, --ntrials N Number of trials [default: 1]\n";
112+
std::cerr << " -v, --verbose Verbose output\n";
113+
std::cerr << " -d, --debug Debug output\n";
114+
exit(1);
115+
}
116+
117+
/**
118+
* @brief Simple command-line argument parser for APB benchmarks.
119+
*/
120+
struct Args {
121+
std::string file;
122+
size_t ntrial = 1;
123+
bool verbose = false;
124+
bool debug = false;
125+
126+
Args(int argc, char* argv[]) {
127+
for (int i = 1; i < argc; ++i) {
128+
std::string arg(argv[i]);
129+
130+
if (arg == "-f" || arg == "--file" || arg == "-i" || arg == "--edgelistfile") {
131+
if (++i >= argc) usage(argv[0], "Missing argument for " + arg);
132+
file = argv[i];
133+
} else if (arg == "-n" || arg == "--ntrials" || arg == "--ntrial") {
134+
if (++i >= argc) usage(argv[0], "Missing argument for " + arg);
135+
ntrial = std::stoul(argv[i]);
136+
} else if (arg == "-v" || arg == "--verbose") {
137+
verbose = true;
138+
} else if (arg == "-d" || arg == "--debug") {
139+
debug = true;
140+
} else if (arg == "-h" || arg == "--help") {
141+
usage(argv[0]);
142+
} else {
143+
usage(argv[0], "Unknown option: " + arg);
144+
}
145+
}
146+
147+
if (file.empty()) {
148+
usage(argv[0], "Input file required (-f)");
149+
}
150+
}
151+
};
152+
153+
} // namespace nw::graph::apb
154+
155+
#endif // NW_GRAPH_APB_COMMON_HPP

0 commit comments

Comments
 (0)