Skip to content

Commit dfd76a6

Browse files
authored
Merge pull request networkit#1283 from fabratu/20250116_ci_coverage_leak
CI: Split coverage and leak build, fix leaks, remove aarch64 wheel build
2 parents b255c5d + 9f453e8 commit dfd76a6

File tree

12 files changed

+185
-107
lines changed

12 files changed

+185
-107
lines changed

.github/workflows/build_wheels.yml

Lines changed: 43 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -54,45 +54,48 @@ jobs:
5454
path: ./wheelhouse/*cp313*.whl
5555
retention-days: ${{ env.ARTIFACT_RETENTION }}
5656

57-
cpython-linux-aarch64:
58-
name: 'Linux CPython (${{ matrix.cibw_archs }}, ${{ matrix.manylinux_image }})'
59-
runs-on: ${{ matrix.os }}
60-
strategy:
61-
matrix:
62-
os: [ubuntu-20.04]
63-
cibw_archs: ["aarch64"]
64-
manylinux_image: ["manylinux2014"]
65-
steps:
66-
- name: Set up QEMU
67-
uses: docker/setup-qemu-action@v3
68-
with:
69-
platforms: all
70-
- uses: actions/checkout@v4
71-
with:
72-
submodules: true
73-
- uses: actions/setup-python@v5
74-
name: Install Python
75-
with:
76-
python-version: '3.12'
77-
- name: Build wheels
78-
uses: pypa/[email protected]
79-
env:
80-
CIBW_BEFORE_BUILD: pip install cython
81-
CIBW_MANYLINUX_X86_64_IMAGE: ${{ matrix.manylinux_image }}
82-
CIBW_ARCHS_LINUX: ${{ matrix.cibw_archs }}
83-
CIBW_BUILD: ${{ github.ref == 'refs/heads/master' && 'cp312-* cp313-*' || 'cp312-*' }}
84-
CIBW_SKIP: "pp* *-musllinux_*"
85-
- uses: actions/upload-artifact@v4
86-
with:
87-
name: 'linux-${{ matrix.cibw_archs }}-cp312-${{ github.run_id }}'
88-
path: ./wheelhouse/*cp312*.whl
89-
retention-days: ${{ env.ARTIFACT_RETENTION }}
90-
- uses: actions/upload-artifact@v4
91-
if: github.ref == 'refs/heads/master'
92-
with:
93-
name: 'linux-${{ matrix.cibw_archs }}-cp313-${{ github.run_id }}'
94-
path: ./wheelhouse/*cp313*.whl
95-
retention-days: ${{ env.ARTIFACT_RETENTION }}
57+
# THIS ACTION IS DISABLED DUE TO SEGMENTATION FAULT IN GCC COMPILER
58+
# Additional note: continue-on-error does not work currently for cibuildwheel:
59+
# https://github.com/pypa/cibuildwheel/issues/1062
60+
# cpython-linux-aarch64:
61+
# name: 'Linux CPython (${{ matrix.cibw_archs }}, ${{ matrix.manylinux_image }})'
62+
# runs-on: ${{ matrix.os }}
63+
# strategy:
64+
# matrix:
65+
# os: [ubuntu-20.04]
66+
# cibw_archs: ["aarch64"]
67+
# manylinux_image: ["manylinux2014"]
68+
# steps:
69+
# - name: Set up QEMU
70+
# uses: docker/setup-qemu-action@v3
71+
# with:
72+
# platforms: all
73+
# - uses: actions/checkout@v4
74+
# with:
75+
# submodules: true
76+
# - uses: actions/setup-python@v5
77+
# name: Install Python
78+
# with:
79+
# python-version: '3.12'
80+
# - name: Build wheels
81+
# uses: pypa/[email protected]
82+
# env:
83+
# CIBW_BEFORE_BUILD: pip install cython
84+
# CIBW_MANYLINUX_X86_64_IMAGE: ${{ matrix.manylinux_image }}
85+
# CIBW_ARCHS_LINUX: ${{ matrix.cibw_archs }}
86+
# CIBW_BUILD: ${{ github.ref == 'refs/heads/master' && 'cp312-* cp313-*' || 'cp312-*' }}
87+
# CIBW_SKIP: "pp* *-musllinux_*"
88+
# - uses: actions/upload-artifact@v4
89+
# with:
90+
# name: 'linux-${{ matrix.cibw_archs }}-cp312-${{ github.run_id }}'
91+
# path: ./wheelhouse/*cp312*.whl
92+
# retention-days: ${{ env.ARTIFACT_RETENTION }}
93+
# - uses: actions/upload-artifact@v4
94+
# if: github.ref == 'refs/heads/master'
95+
# with:
96+
# name: 'linux-${{ matrix.cibw_archs }}-cp313-${{ github.run_id }}'
97+
# path: ./wheelhouse/*cp313*.whl
98+
# retention-days: ${{ env.ARTIFACT_RETENTION }}
9699

97100
cpython-macos:
98101
name: 'macOS CPython (${{ matrix.buildplat[1] }})'
@@ -235,7 +238,7 @@ jobs:
235238
if: needs.check-release-tag.outputs.is-release == 'true' && github.repository == 'networkit/networkit'
236239
name: 'PyPi release upload'
237240
runs-on: ubuntu-22.04
238-
needs: [cpython-macos, cpython-linux-aarch64, cpython-linux-x86_64, cpython-windows, source-distribution, check-release-tag]
241+
needs: [cpython-macos, cpython-linux-x86_64, cpython-windows, source-distribution, check-release-tag]
239242
steps:
240243
- uses: actions/download-artifact@v4
241244
with:

.github/workflows/ci.yml

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -306,7 +306,7 @@ jobs:
306306
run: ${{ github.workspace }}/.github/workflows/scripts/clang_tidy.sh
307307
shell: bash
308308

309-
linux-build-core-sanitizers-coverage:
309+
linux-build-coverage:
310310
name: "Linux (gcc-10, CPython 3.12): coverage"
311311
runs-on: ubuntu-22.04
312312
env:
@@ -330,7 +330,7 @@ jobs:
330330
with:
331331
submodules: true
332332
- name: Prepare environment and run checks
333-
run: ${{ github.workspace }}/.github/workflows/scripts/core_sanitizers_coverage.sh
333+
run: ${{ github.workspace }}/.github/workflows/scripts/coverage.sh
334334
shell: bash
335335
timeout-minutes: 180
336336
- name: Create C++ coverage
@@ -354,6 +354,31 @@ jobs:
354354
. pyenv/bin/activate
355355
python3 ${{ github.workspace }}/.github/workflows/scripts/upload_coverage.py
356356
357+
linux-build-leak:
358+
name: "Linux (gcc-10, CPython 3.12): leak checks"
359+
runs-on: ubuntu-22.04
360+
env:
361+
UBSAN_OPTIONS: print_stacktrace=1:halt_on_error=1:report_error_type=1:suppressions=../UBSAN.filter
362+
steps:
363+
- name: Install prerequisites
364+
run: |
365+
wget -qO- https://apt.llvm.org/llvm-snapshot.gpg.key | sudo tee /etc/apt/trusted.gpg.d/apt.llvm.org.asc
366+
echo "deb http://apt.llvm.org/jammy llvm-toolchain-jammy-17 main" | sudo tee /etc/apt/sources.list.d/llvm17.list
367+
sudo apt-get update
368+
sudo apt-get install libomp-17-dev clang-17 clang-tidy-17 ninja-build
369+
- name: Checkout
370+
uses: actions/checkout@v4
371+
with:
372+
submodules: true
373+
- name: Prepare environment and run checks
374+
run: |
375+
mkdir build && cd build
376+
cmake -GNinja -DNETWORKIT_BUILD_TESTS=ON -DCMAKE_BUILD_TYPE=Debug -DNETWORKIT_CXX_STANDARD=${{ env.CXX_STANDARD }} -DNETWORKIT_WITH_SANITIZERS=leak -DCMAKE_CXX_COMPILER=/usr/bin/clang++-17 ..
377+
ninja
378+
ctest -V -C Debug
379+
shell: bash
380+
timeout-minutes: 180
381+
357382
windows-build-msvc:
358383
name: "Windows (msvc 14.X): ${{ matrix.build-configuration }}"
359384
runs-on: windows-2022

.github/workflows/scripts/core_sanitizers_coverage.sh renamed to .github/workflows/scripts/coverage.sh

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,16 @@
22

33
python3 -m venv pyenv && . pyenv/bin/activate
44
pip3 install --upgrade pip
5-
pip3 install coveralls cython gcovr matplotlib requests setuptools tabulate numpy networkx ipycytoscape seaborn plotly
5+
pip3 install coveralls cython gcovr matplotlib requests setuptools tabulate numpy networkx ipycytoscape seaborn plotly anywidget
66

77
mkdir core_build && cd "$_"
88
export CPU_COUNT=$(python3 $GITHUB_WORKSPACE/.github/workflows/scripts/get_core_count.py)
9-
cmake -DNETWORKIT_BUILD_TESTS=ON -DCMAKE_BUILD_TYPE=Debug -DNETWORKIT_WITH_SANITIZERS=leak -DNETWORKIT_COVERAGE=ON ..
9+
cmake -DNETWORKIT_BUILD_TESTS=ON -DCMAKE_BUILD_TYPE=Debug -DNETWORKIT_COVERAGE=ON ..
1010
make -j$CPU_COUNT
1111

12-
ctest -V
13-
1412
cd ..
13+
./core_build/networkit_tests -t
14+
1515
export CMAKE_LIBRARY_PATH=${CMAKE_LIBRARY_PATH:+$CMAKE_LIBRARY_PATH:}$(pwd)/core_build
1616
export LD_LIBRARY_PATH=${LD_LIBRARY_PATH:+$LD_LIBRARY_PATH:}$(pwd)/core_build
1717

UBSAN.filter

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
bounds:random.tcc

include/networkit/community/LouvainMapEquation.hpp

Lines changed: 8 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
namespace NetworKit {
1818

1919
class LouvainMapEquation : public CommunityDetectionAlgorithm {
20-
private:
20+
public:
2121
enum class ParallelizationType : uint8_t {
2222
NONE,
2323
RELAX_MAP,
@@ -27,6 +27,7 @@ class LouvainMapEquation : public CommunityDetectionAlgorithm {
2727
Synchronous = SYNCHRONOUS
2828
};
2929

30+
public:
3031
/**
3132
* @param[in] G input graph
3233
* @param[in] hierarchical use recursive coarsening
@@ -37,10 +38,9 @@ class LouvainMapEquation : public CommunityDetectionAlgorithm {
3738
* synchronous -> work on stale cuts and volumes, update in second step
3839
*
3940
*/
40-
explicit LouvainMapEquation(const Graph &graph, bool hierarchical, count maxIterations,
41-
ParallelizationType parallelizationType);
42-
43-
public:
41+
explicit LouvainMapEquation(const Graph &graph, bool hierarchical = false,
42+
count maxIterations = 32,
43+
std::string_view parallelizationStrategy = "relaxmap");
4444
/**
4545
* @param[in] G input graph
4646
* @param[in] hierarchical use recursive coarsening
@@ -51,11 +51,8 @@ class LouvainMapEquation : public CommunityDetectionAlgorithm {
5151
* synchronous -> work on stale cuts and volumes, update in second step
5252
*
5353
*/
54-
explicit LouvainMapEquation(const Graph &graph, bool hierarchical = false,
55-
count maxIterations = 32,
56-
std::string_view parallelizationStrategy = "relaxmap")
57-
: LouvainMapEquation(graph, hierarchical, maxIterations,
58-
convertStringToParallelizationType(parallelizationStrategy)) {}
54+
explicit LouvainMapEquation(const Graph &graph, bool hierarchical, count maxIterations,
55+
ParallelizationType parallelizationType);
5956

6057
void run() override;
6158

@@ -74,8 +71,8 @@ class LouvainMapEquation : public CommunityDetectionAlgorithm {
7471
static_assert(std::is_trivially_destructible<Move>::value,
7572
"LouvainMapEquation::Move struct is not trivially destructible");
7673

77-
const bool parallel;
7874
ParallelizationType parallelizationType;
75+
bool parallel;
7976

8077
bool hierarchical;
8178
count maxIterations;
@@ -122,19 +119,6 @@ class LouvainMapEquation : public CommunityDetectionAlgorithm {
122119
return std::make_pair(i * chunkSize, std::min(n, (i + 1) * chunkSize));
123120
}
124121

125-
ParallelizationType
126-
convertStringToParallelizationType(std::string_view parallelizationStrategy) const {
127-
if (parallelizationStrategy == "none")
128-
return ParallelizationType::NONE;
129-
else if (parallelizationStrategy == "relaxmap")
130-
return ParallelizationType::RELAX_MAP;
131-
else if (parallelizationStrategy == "synchronous")
132-
return ParallelizationType::SYNCHRONOUS;
133-
else
134-
throw std::runtime_error("Invalid parallelization type for map equation Louvain: "
135-
+ std::string(parallelizationStrategy));
136-
}
137-
138122
#ifndef NDEBUG
139123
long double sumPLogPwAlpha = 0;
140124
long double sumPLogPClusterCut = 0;

include/networkit/graph/GraphTools.hpp

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -409,6 +409,19 @@ std::pair<Graph, node> createAugmentedGraph(const Graph &G);
409409
*/
410410
void sortEdgesByWeight(Graph &G, bool decreasing = false);
411411

412+
/**
413+
* Given a directed graph G, the topology sort algorithm creates one valid topology order of nodes.
414+
* Undirected graphs are not accepted as input, since a topology sort is a linear ordering of
415+
* vertices such that for every edge u -> v, node u comes before v in the ordering.
416+
* Node ids must either be continuous or you must provide a continuous node id mapping.
417+
*
418+
* This is a helper function. Instead of calling it via GraphTools, it is also possible to create a
419+
* TopologicalSort-object from the base-class.
420+
* @param G Directed input graph
421+
* @return A vector of node-ids sorted according to their topology.
422+
*/
423+
std::vector<node> topologicalSort(const Graph &G);
424+
412425
/**
413426
* Given a directed graph G, the topology sort algorithm creates one valid topology order of nodes.
414427
* Undirected graphs are not accepted as input, since a topology sort is a linear ordering of
@@ -419,10 +432,11 @@ void sortEdgesByWeight(Graph &G, bool decreasing = false);
419432
* TopologicalSort-object from the base-class.
420433
* @param G Directed input graph
421434
* @param nodeIdMapping Optional continuous node id mapping
435+
* @param checkMapping Check whether the given node id map is continuous.
422436
* @return A vector of node-ids sorted according to their topology.
423437
*/
424438
std::vector<node> topologicalSort(const Graph &G,
425-
const std::unordered_map<node, node> &nodeIdMapping = {},
439+
const std::unordered_map<node, node> &nodeIdMapping,
426440
bool checkMapping = false);
427441

428442
/**

include/networkit/graph/TopologicalSort.hpp

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,22 @@ namespace NetworKit {
2222
class TopologicalSort final : public Algorithm {
2323
public:
2424
/**
25-
* Initialize the topological sort algorithm by passing an input graph. Note that topological
26-
* sort is defined for directed graphs only. The node id mapping must be a continuous.
25+
* Initialize the topological sort algorithm by passing an input graph.
2726
*
2827
* @param G The input graph.
2928
*/
30-
TopologicalSort(const Graph &G, const std::unordered_map<node, node> &nodeIdMapping = {},
29+
TopologicalSort(const Graph &G);
30+
31+
/**
32+
* Initialize the topological sort algorithm by passing an input graph and an node id map.
33+
* The node id mapping must be a continuous. This can be checked by setting checkMapping to
34+
* true.
35+
*
36+
* @param G The input graph.
37+
* @param nodeIdMapping Node id mapping from non-continuous to continuous ids.
38+
* @param checkMapping Check whether the given node id map is continuous.
39+
*/
40+
TopologicalSort(const Graph &G, const std::unordered_map<node, node> &nodeIdMapping,
3141
bool checkMapping = false);
3242

3343
/**
@@ -52,7 +62,7 @@ class TopologicalSort final : public Algorithm {
5262

5363
std::optional<std::unordered_map<node, node>> computedNodeIdMap;
5464

55-
const std::unordered_map<node, node> &nodeIdMap;
65+
const std::unordered_map<node, node> *nodeIdMap = nullptr;
5666

5767
// Used to mark the status of each node, one vector per thread
5868
std::vector<NodeMark> topSortMark;

networkit/cpp/centrality/test/CentralityGTest.cpp

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1961,21 +1961,22 @@ TEST_F(CentralityGTest, testApproxElectricalCloseness) {
19611961
}
19621962
}
19631963

1964-
TEST_P(CentralityGTest, testGroupClosenessGrowShrink) {
1965-
if (isDirected()) { // directed graphs are not supported
1966-
Graph G(10, isWeighted(), true);
1967-
std::array<node, 1> group = {{0}};
1968-
EXPECT_THROW(GroupClosenessGrowShrink(G, group.begin(), group.end()), std::runtime_error);
1969-
return;
1970-
}
1964+
TEST_F(CentralityGTest, testGroupClosenessDirected) {
1965+
// directed graphs are not supported
1966+
Graph G(10, false, true);
1967+
std::array<node, 1> group = {{0}};
1968+
EXPECT_THROW(GroupClosenessGrowShrink(G, group.begin(), group.end()), std::runtime_error);
1969+
}
19711970

1972-
{ // Empty input groups are not supported
1973-
Graph G(10, isWeighted(), false);
1974-
std::vector<node> emptyGroup;
1975-
EXPECT_THROW(GroupClosenessGrowShrink(G, emptyGroup.begin(), emptyGroup.end()),
1976-
std::runtime_error);
1977-
}
1971+
TEST_F(CentralityGTest, testGroupClosenessEmptyGroups) {
1972+
// Empty input groups are not supported
1973+
Graph G(10);
1974+
std::vector<node> emptyGroup;
1975+
EXPECT_THROW(GroupClosenessGrowShrink(G, emptyGroup.begin(), emptyGroup.end()),
1976+
std::runtime_error);
1977+
}
19781978

1979+
TEST_P(CentralityGTest, testGroupClosenessGrowShrink) {
19791980
const count k = 5;
19801981
auto G = EdgeListReader{'\t', 0, "#", false, false}.read("input/MIT8.edgelist");
19811982
G = ConnectedComponents::extractLargestConnectedComponent(G);

networkit/cpp/community/LouvainMapEquation.cpp

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,37 @@
2121

2222
namespace NetworKit {
2323

24+
LouvainMapEquation::ParallelizationType
25+
convertStringToParallelizationType(std::string_view parallelizationStrategy) {
26+
if (parallelizationStrategy == "none")
27+
return LouvainMapEquation::ParallelizationType::NONE;
28+
else if (parallelizationStrategy == "relaxmap")
29+
return LouvainMapEquation::ParallelizationType::RELAX_MAP;
30+
else if (parallelizationStrategy == "synchronous")
31+
return LouvainMapEquation::ParallelizationType::SYNCHRONOUS;
32+
else
33+
throw std::runtime_error("Invalid parallelization type for map equation Louvain: "
34+
+ std::string(parallelizationStrategy));
35+
}
36+
2437
LouvainMapEquation::LouvainMapEquation(const Graph &graph, bool hierarchical, count maxIterations,
2538
ParallelizationType parallelizationType)
26-
: CommunityDetectionAlgorithm(graph), parallel(parallelizationType > ParallelizationType::NONE),
27-
parallelizationType(parallelizationType), hierarchical(hierarchical),
39+
: CommunityDetectionAlgorithm(graph), parallelizationType(parallelizationType),
40+
parallel(parallelizationType > ParallelizationType::NONE), hierarchical(hierarchical),
41+
maxIterations(maxIterations), clusterCut(graph.upperNodeIdBound()),
42+
clusterVolume(graph.upperNodeIdBound()),
43+
locks(parallelizationType == ParallelizationType::RELAX_MAP ? graph.upperNodeIdBound() : 0),
44+
nextPartition(
45+
parallelizationType == ParallelizationType::SYNCHRONOUS ? graph.upperNodeIdBound() : 0),
46+
ets_neighborClusterWeights(parallel ? Aux::getMaxNumberOfThreads() : 1) {
47+
result = Partition(graph.upperNodeIdBound());
48+
}
49+
50+
LouvainMapEquation::LouvainMapEquation(const Graph &graph, bool hierarchical, count maxIterations,
51+
std::string_view parallelizationStrategy)
52+
: CommunityDetectionAlgorithm(graph),
53+
parallelizationType(convertStringToParallelizationType(parallelizationStrategy)),
54+
parallel(parallelizationType != ParallelizationType::NONE), hierarchical(hierarchical),
2855
maxIterations(maxIterations), clusterCut(graph.upperNodeIdBound()),
2956
clusterVolume(graph.upperNodeIdBound()),
3057
locks(parallelizationType == ParallelizationType::RELAX_MAP ? graph.upperNodeIdBound() : 0),

0 commit comments

Comments
 (0)