Skip to content

Commit

Permalink
Log system info upon startup (#25)
Browse files Browse the repository at this point in the history
Add log_system_info() which logs CPU & RAM info, distribution and libc version.
  • Loading branch information
Jongy authored Apr 12, 2021
1 parent adf8b61 commit 204e333
Show file tree
Hide file tree
Showing 4 changed files with 64 additions and 4 deletions.
6 changes: 5 additions & 1 deletion gprofiler/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
from .java import JavaProfiler
from .perf import SystemProfiler
from .python import PythonProfiler
from .utils import is_root, run_process, get_iso8061_format_time, resource_path, TEMPORARY_STORAGE_PATH
from .utils import is_root, run_process, get_iso8061_format_time, resource_path, log_system_info, TEMPORARY_STORAGE_PATH

logger: Logger

Expand Down Expand Up @@ -253,6 +253,10 @@ def main():

try:
logger.info(f"Running gprofiler (version {__version__})...")
try:
log_system_info()
except Exception:
logger.exception("Encountered an exception while getting basic system info")

if not verify_preconditions():
sys.exit(1)
Expand Down
59 changes: 57 additions & 2 deletions gprofiler/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,17 @@
import re
import shutil
import subprocess
import platform
import ctypes
from functools import lru_cache
from subprocess import CompletedProcess, Popen, TimeoutExpired
from threading import Event
from typing import Iterator, Union, List, Optional
from threading import Event, Thread
from typing import Iterator, Union, List, Optional, Tuple
from pathlib import Path

import importlib_resources
import psutil
import distro # type: ignore
from psutil import Process

from gprofiler.exceptions import CalledProcessError, ProcessStoppedException, ProgramMissingException
Expand Down Expand Up @@ -187,3 +190,55 @@ def assert_program_installed(program: str):
_INSTALLED_PROGRAMS_CACHE.append(program)
else:
raise ProgramMissingException(program)


def get_libc_version() -> Tuple[str, str]:
# platform.libc_ver fails for musl, sadly (produces empty results).
# so we'll run "ldd --version" and extract the version string from it.
ldd_version = subprocess.run(
["ldd", "--version"], stdout=subprocess.PIPE, stderr=subprocess.STDOUT, encoding="ascii"
).stdout
# catches GLIBC & EGLIBC
m = re.search(r"GLIBC (.*?)\)", ldd_version)
if m is not None:
return ("glibc", m.group(1))
# musl
m = re.search(r"musl libc.*?\nVersion (.*?)\n", ldd_version, re.M)
if m is not None:
return ("musl", m.group(1))

return ("unknown", ldd_version)


def log_system_info():
uname = platform.uname()
logger.info(f"Kernel uname release: {uname.release}")
logger.info(f"Kernel uname version: {uname.version}")
logger.info(f"Total CPUs: {os.cpu_count()}")
logger.info(f"Total RAM: {psutil.virtual_memory().total / (1 << 30):.2f} GB")

# we can't setns(CLONE_NEWNS) in a multithreaded program (unless we unshare(CLONE_NEWNS) before)
# so, we start a new thread, unshare() & setns() it, get our needed information and then stop this thread
# (so we don't keep unshared threads running around)
results = []

def get_distro_and_libc():
# move to host mount NS for distro & ldd.
if not is_same_ns(1, "mnt"):
libc = ctypes.CDLL("libc.so.6")

CLONE_NEWNS = 0x00020000
if libc.unshare(CLONE_NEWNS) != 0 or libc.setns(os.open("/proc/1/ns/mnt", os.O_RDONLY), CLONE_NEWNS) != 0:
raise ValueError("Failed to unshare() and setns()")

# now, distro will read the files on host.
results.append(distro.linux_distribution())
results.append(get_libc_version())

t = Thread(target=get_distro_and_libc)
t.start()
t.join()
assert len(results) == 2, f"only {len(results)} results, expected 2"

logger.info(f"Linux distribution: {results[0]}")
logger.info(f"libc version: {results[1]}")
1 change: 1 addition & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ importlib-resources==5.1.0
psutil==5.8.0
requests==2.25.1
ConfigArgParse==1.3
distro==1.5.0
2 changes: 1 addition & 1 deletion tests/test_sanity.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
# Copyright (c) Granulate. All rights reserved.
# Licensed under the AGPL3 License. See LICENSE.md in the project root for license information.
#
import pytest
import pytest # type: ignore
from glob import glob
from pathlib import Path
from threading import Event
Expand Down

0 comments on commit 204e333

Please sign in to comment.