Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make libnuma into a soft dependency #196

Merged
merged 4 commits into from
Apr 30, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/activate_miniconda.sh
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@ if [ '!' -d $HOME/miniconda/bin ]; then
bash "$HOME/.cache/miniconda/mambaforge.sh" -f -b -p $HOME/miniconda
fi
export PATH=$HOME/miniconda/bin:$PATH
source activate
. activate
22 changes: 22 additions & 0 deletions .github/workflows/python.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,28 @@ jobs:
name: conda-pkgs-${{matrix.os}}
path: /Users/runner/build

test_conda_package_install:
needs: build_and_test_conda_package
runs-on: ubuntu-18.04
strategy:
matrix:
image:
- ubuntu:16.04
- ubuntu:latest
- centos:7
- centos:latest
Comment on lines +116 to +122
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ddn0 Did I over do the docker image matrix? Should I include anything else? They take about 5min each and all run in parallel after build_and_test_conda_package finishes.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I might add ubuntu:18.04 and ubuntu:20.04 explicitly (in addition to ubuntu:latest). But I don't have a strong preference.

steps:
- name: Checkout repo
uses: actions/checkout@v2
with:
submodules: 'recursive'
- name: Download conda packages
uses: actions/download-artifact@v2
with:
name: conda-pkgs-ubuntu-18.04
path: pkgs
- name: Install in docker container
run: python3 tests/install_conda_packages_test.py pkgs ${{matrix.image}}

lint:
runs-on: ${{matrix.os}}
Expand Down
1 change: 0 additions & 1 deletion conda_recipe/meta.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,6 @@ outputs:
test:
requires:
- {{ compiler('cxx') }}
- {{ cdt('numactl') }}
- cmake>=3.17
- make
files:
Expand Down
4 changes: 3 additions & 1 deletion libgalois/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,9 @@ endif()

if(NUMA_FOUND)
target_compile_definitions(katana_galois PRIVATE KATANA_USE_NUMA)
target_link_libraries(katana_galois PRIVATE ${NUMA_LIBRARY})
file(REAL_PATH ${NUMA_LIBRARY} NUMA_LIBRARY_RESOLVED)
cmake_path(GET NUMA_LIBRARY_RESOLVED FILENAME KATANA_LIBNUMA_SO_NAME)
target_compile_definitions(katana_galois PRIVATE "KATANA_LIBNUMA_SO_NAME=\"${KATANA_LIBNUMA_SO_NAME}\"")
else()
message(WARNING "No NUMA Support. Likely poor performance for multi-socket systems.")
endif()
Expand Down
98 changes: 65 additions & 33 deletions libgalois/src/HWTopoLinux.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
* Documentation, or loss or inaccuracy of data of any kind.
*/

#include <dlfcn.h>

#include <algorithm>
#include <array>
#include <cassert>
Expand All @@ -34,7 +36,6 @@

#ifdef KATANA_USE_NUMA
#include <numa.h>
#include <numaif.h>
#endif

#ifdef KATANA_USE_SCHED_SETAFFINITY
Expand All @@ -57,44 +58,68 @@ struct cpuinfo {

bool
operator<(const cpuinfo& lhs, const cpuinfo& rhs) {
if (lhs.smt != rhs.smt)
if (lhs.smt != rhs.smt) {
return lhs.smt < rhs.smt;
if (lhs.physid != rhs.physid)
}
if (lhs.physid != rhs.physid) {
return lhs.physid < rhs.physid;
if (lhs.coreid != rhs.coreid)
}
if (lhs.coreid != rhs.coreid) {
return lhs.coreid < rhs.coreid;
}
return lhs.proc < rhs.proc;
}

#ifdef KATANA_USE_NUMA
int (*dynamic_numa_available)() = nullptr;
int (*dynamic_numa_num_configured_nodes)() = nullptr;
int (*dynamic_numa_node_of_cpu)(int cpu) = nullptr;

void
LoadLibNuma() {
// KATANA_LIBNUMA_SO_NAME is defined in libgalois/CMakeLists.txt
auto* lib = dlopen(KATANA_LIBNUMA_SO_NAME, RTLD_LAZY);
if (!lib) {
return;
}
#define LOAD_SYM(name) \
dynamic_##name = reinterpret_cast<decltype(&name)>(dlsym(lib, #name))
LOAD_SYM(numa_available);
LOAD_SYM(numa_num_configured_nodes);
LOAD_SYM(numa_node_of_cpu);
#undef LOAD_SYM
}
#endif

unsigned
getNumaNode(cpuinfo& c) {
static bool warnOnce = false;
getNumaNode(const cpuinfo& c) {
#ifdef KATANA_USE_NUMA
static bool numaAvail = false;

if (!warnOnce) {
warnOnce = true;
numaAvail = numa_available() >= 0;
numaAvail = numaAvail && numa_num_configured_nodes() > 0;
if (!numaAvail)
katana::gWarn(
static std::once_flag load_numa_once;
static bool numa_avail = false;

std::call_once(load_numa_once, [&]() {
LoadLibNuma();
numa_avail = dynamic_numa_available && dynamic_numa_available() >= 0;
numa_avail = numa_avail && dynamic_numa_num_configured_nodes() > 0;
if (!numa_avail) {
arthurp marked this conversation as resolved.
Show resolved Hide resolved
KATANA_LOG_WARN(
"Numa support configured but not present at runtime. "
"Assuming numa topology matches socket topology.");
}
}
});

if (!numaAvail)
if (!numa_avail) {
return c.physid;
int i = numa_node_of_cpu(c.proc);
if (i < 0)
KATANA_SYS_DIE("failed finding numa node for ", c.proc);
}
int i = dynamic_numa_node_of_cpu(c.proc);
if (i < 0) {
KATANA_LOG_FATAL("failed finding numa node for {}", c.proc);
}
return i;
#else
if (!warnOnce) {
warnOnce = true;
katana::gWarn(
"Numa Support Not configured (install libnuma-dev). "
"Assuming numa topology matches socket topology.");
}
KATANA_WARN_ONCE(
"Numa Support Not configured (install libnuma-dev). "
"Assuming numa topology matches socket topology.");
return c.physid;
#endif
}
Expand Down Expand Up @@ -141,35 +166,40 @@ parseCPUInfo() {
unsigned
countSockets(const std::vector<cpuinfo>& info) {
std::set<unsigned> pkgs;
for (auto& c : info)
for (auto& c : info) {
pkgs.insert(c.physid);
}
return pkgs.size();
}

unsigned
countCores(const std::vector<cpuinfo>& info) {
std::set<std::pair<int, int>> cores;
for (auto& c : info)
for (auto& c : info) {
cores.insert(std::make_pair(c.physid, c.coreid));
}
return cores.size();
}

unsigned
countNumaNodes(const std::vector<cpuinfo>& info) {
std::set<unsigned> nodes;
for (auto& c : info)
for (auto& c : info) {
nodes.insert(c.numaNode);
}
return nodes.size();
}

void
markSMT(std::vector<cpuinfo>& info) {
for (unsigned int i = 1; i < info.size(); ++i)
for (unsigned int i = 1; i < info.size(); ++i) {
if (info[i - 1].physid == info[i].physid &&
info[i - 1].coreid == info[i].coreid)
info[i - 1].coreid == info[i].coreid) {
info[i].smt = true;
else
} else {
info[i].smt = false;
}
}
}

std::vector<int>
Expand Down Expand Up @@ -210,12 +240,14 @@ void
markValid(std::vector<cpuinfo>& info) {
auto v = parseCPUSet();
if (v.empty()) {
for (auto& c : info)
for (auto& c : info) {
c.valid = true;
}
} else {
std::sort(v.begin(), v.end());
for (auto& c : info)
for (auto& c : info) {
c.valid = std::binary_search(v.begin(), v.end(), c.proc);
}
}
}

Expand Down
4 changes: 2 additions & 2 deletions scripts/katana_version/version.py
Original file line number Diff line number Diff line change
Expand Up @@ -194,8 +194,8 @@ def get_config_version(k_commit, repo: Repo, version_file, no_dev=False) -> vers
version_str = version_file.read()
elif version_file:
# We have no git information. Wing it.
with open(Path(__file__).parent.parent.parent / CONFIG_VERSION_PATH, "rt") as version_file:
version_str = version_file.read()
with open(version_file, "rt") as version_fi:
version_str = version_fi.read()
else:
# We have no information. Something is really broken. Still don't crash to allow builds.
version_str = "0.0.0"
Expand Down
59 changes: 59 additions & 0 deletions tests/install_conda_packages_test.Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
ARG BASE_IMAGE
FROM ${BASE_IMAGE} AS base_with_conda

COPY download_miniconda.sh /
COPY activate_miniconda.sh /

ENV DEBIAN_FRONTEND=noninteractive
ENV TZ=America/Chicago
ENV APT_GET="apt-get --yes --quiet"
ENV YUM="yum -y"

RUN set -eux; \
if command -v yum > /dev/null; then \
${YUM} update; \
${YUM} install curl; \
${YUM} clean all; \
else \
${APT_GET} update; \
${APT_GET} dist-upgrade; \
${APT_GET} install curl; \
${APT_GET} clean; \
fi

RUN set -eu; \
bash /download_miniconda.sh ubuntu-xxx; \
. /activate_miniconda.sh;

ARG CONDA_CLEAN="conda clean --quiet --yes --all"

RUN set -eu; \
. /activate_miniconda.sh; \
mamba update --quiet --yes --all; \
${CONDA_CLEAN}

FROM base_with_conda AS pre_install

COPY packages /packages

FROM pre_install AS test_python
ARG CONDA_CLEAN="conda clean --quiet --yes --all"
ARG MAMBA_INSTALL="mamba install --quiet --yes --channel /packages"

RUN set -eu ; . /activate_miniconda.sh; set -x ; \
${MAMBA_INSTALL} katana-python; \
${CONDA_CLEAN}

RUN set -eu ; . /activate_miniconda.sh; set -x ; \
python -c "import katana.analytics; katana.analytics.bfs; print(katana.__version__)"

FROM pre_install AS test_tools
ARG CONDA_CLEAN="conda clean --quiet --yes --all"
ARG MAMBA_INSTALL="mamba install --quiet --yes --channel /packages"

RUN set -eu ; . /activate_miniconda.sh; set -x ; \
${MAMBA_INSTALL} katana-tools; \
${CONDA_CLEAN}

RUN set -eu ; . /activate_miniconda.sh; set -x ; \
graph-convert --version
37 changes: 37 additions & 0 deletions tests/install_conda_packages_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
#! /bin/python

import argparse
from pathlib import Path
from subprocess import Popen, PIPE
from sys import stderr
import tarfile


def main():
parser = argparse.ArgumentParser(
description="Install katana packages in a docker image and test them. " "Only runs a trivial test."
)
parser.add_argument("package_dir", type=Path, help="The directory containing the conda packages to install.")
parser.add_argument("docker_image", type=str, help="The docker image to use.")

args = parser.parse_args()

docker_proc = Popen(["docker", "build", "-", "--build-arg", f"BASE_IMAGE={args.docker_image}",], stdin=PIPE)
with docker_proc.stdin, tarfile.open(fileobj=docker_proc.stdin, mode="w:gz") as context_tar:
context_tar.add(Path(args.package_dir).absolute(), arcname="packages")
context_tar.add(Path(__file__).parent / "install_conda_packages_test.Dockerfile", arcname="Dockerfile")
context_tar.add(
Path(__file__).parent.parent / ".github" / "workflows" / "download_miniconda.sh",
arcname="download_miniconda.sh",
)
context_tar.add(
Path(__file__).parent.parent / ".github" / "workflows" / "activate_miniconda.sh",
arcname="activate_miniconda.sh",
)
err_code = docker_proc.wait()
if err_code != 0:
print(f"Failed to install and test Conda packages from {args.package_dir} in {args.docker_image}", file=stderr)


if __name__ == "__main__":
main()