Profiling is easy now :)
This commit is contained in:
parent
f134c5752b
commit
dd4324bad4
|
@ -371,50 +371,17 @@ def runCmd(args: cli.Args):
|
||||||
os.environ["CK_BUILDDIR"] = product.target.builddir
|
os.environ["CK_BUILDDIR"] = product.target.builddir
|
||||||
os.environ["CK_COMPONENT"] = product.component.id
|
os.environ["CK_COMPONENT"] = product.component.id
|
||||||
|
|
||||||
if debug:
|
try:
|
||||||
if debugger == "lldb":
|
command = [str(product.path), *args.extra]
|
||||||
shell.exec(
|
|
||||||
"lldb",
|
if debug:
|
||||||
*(("-o", "b main") if wait else ()),
|
shell.debug(command, debugger=debugger, wait=wait)
|
||||||
*("-o", "run"),
|
elif profile:
|
||||||
str(product.path),
|
shell.profile(command)
|
||||||
*args.extra,
|
|
||||||
)
|
|
||||||
elif debugger == "gdb":
|
|
||||||
shell.exec(
|
|
||||||
"gdb",
|
|
||||||
*(("-ex", "b main") if wait else ()),
|
|
||||||
*("-ex", "run"),
|
|
||||||
str(product.path),
|
|
||||||
*args.extra,
|
|
||||||
)
|
|
||||||
else:
|
else:
|
||||||
raise RuntimeError(f"Unknown debugger {debugger}")
|
shell.exec(*command)
|
||||||
elif profile:
|
except Exception as e:
|
||||||
# Profile the executable using perf
|
cli.error(e)
|
||||||
shell.exec(
|
|
||||||
"perf",
|
|
||||||
"record",
|
|
||||||
"-g",
|
|
||||||
"-o",
|
|
||||||
"perf.data",
|
|
||||||
"--call-graph",
|
|
||||||
"dwarf",
|
|
||||||
str(object=product.path),
|
|
||||||
*args.extra,
|
|
||||||
)
|
|
||||||
|
|
||||||
# Run this command using subprocess
|
|
||||||
# perf script -i perf.data | speedscope -
|
|
||||||
import subprocess
|
|
||||||
|
|
||||||
proc = subprocess.Popen(
|
|
||||||
["perf", "script", "-i", "perf.data"], stdout=subprocess.PIPE
|
|
||||||
)
|
|
||||||
subprocess.run(["speedscope", "-"], stdin=proc.stdout)
|
|
||||||
proc.wait()
|
|
||||||
else:
|
|
||||||
shell.exec(str(product.path), *args.extra)
|
|
||||||
|
|
||||||
|
|
||||||
@cli.command("t", "builder/test", "Run all test targets")
|
@cli.command("t", "builder/test", "Run all test targets")
|
||||||
|
|
|
@ -24,6 +24,7 @@ GLOBAL_CK_DIR = os.path.join(os.path.expanduser("~"), ".cutekit")
|
||||||
BUILD_DIR = os.path.join(PROJECT_CK_DIR, "build")
|
BUILD_DIR = os.path.join(PROJECT_CK_DIR, "build")
|
||||||
CACHE_DIR = os.path.join(PROJECT_CK_DIR, "cache")
|
CACHE_DIR = os.path.join(PROJECT_CK_DIR, "cache")
|
||||||
EXTERN_DIR = os.path.join(PROJECT_CK_DIR, "extern")
|
EXTERN_DIR = os.path.join(PROJECT_CK_DIR, "extern")
|
||||||
|
TMP_DIR = os.path.join(PROJECT_CK_DIR, "tmp")
|
||||||
SRC_DIR = "src"
|
SRC_DIR = "src"
|
||||||
META_DIR = "meta"
|
META_DIR = "meta"
|
||||||
TARGETS_DIR = os.path.join(META_DIR, "targets")
|
TARGETS_DIR = os.path.join(META_DIR, "targets")
|
||||||
|
|
|
@ -69,14 +69,15 @@ def combineMixins(*mixins: Mixin) -> Mixin:
|
||||||
mixins: dict[str, Mixin] = {
|
mixins: dict[str, Mixin] = {
|
||||||
"cache": mixinCache,
|
"cache": mixinCache,
|
||||||
"debug": mixinDebug,
|
"debug": mixinDebug,
|
||||||
"asan": makeMixinSan("address"),
|
"asan": combineMixins(makeMixinSan("address"), makeMixinSan("leak")),
|
||||||
"msan": makeMixinSan("memory"),
|
"msan": makeMixinSan("memory"),
|
||||||
"tsan": makeMixinSan("thread"),
|
"tsan": makeMixinSan("thread"),
|
||||||
"ubsan": makeMixinSan("undefined"),
|
"ubsan": makeMixinSan("undefined"),
|
||||||
"sanitize": combineMixins(
|
"lsan": makeMixinSan("leak"),
|
||||||
|
"san": combineMixins(
|
||||||
makeMixinSan("address"),
|
makeMixinSan("address"),
|
||||||
makeMixinSan("memory"),
|
makeMixinSan("undefined"),
|
||||||
makeMixinSan("thread"),
|
makeMixinSan("leak"),
|
||||||
),
|
),
|
||||||
"tune": makeMixinTune("native"),
|
"tune": makeMixinTune("native"),
|
||||||
"release": combineMixins(
|
"release": combineMixins(
|
||||||
|
|
|
@ -12,6 +12,7 @@ import logging
|
||||||
import tempfile
|
import tempfile
|
||||||
import dataclasses as dt
|
import dataclasses as dt
|
||||||
|
|
||||||
|
from pathlib import Path
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
from . import const
|
from . import const
|
||||||
|
|
||||||
|
@ -134,6 +135,7 @@ def wget(url: str, path: Optional[str] = None) -> str:
|
||||||
|
|
||||||
def exec(*args: str, quiet: bool = False, cwd: Optional[str] = None) -> bool:
|
def exec(*args: str, quiet: bool = False, cwd: Optional[str] = None) -> bool:
|
||||||
_logger.debug(f"Executing {args}")
|
_logger.debug(f"Executing {args}")
|
||||||
|
cmdName = Path(args[0]).name
|
||||||
|
|
||||||
try:
|
try:
|
||||||
proc = subprocess.run(
|
proc = subprocess.run(
|
||||||
|
@ -156,34 +158,86 @@ def exec(*args: str, quiet: bool = False, cwd: Optional[str] = None) -> bool:
|
||||||
raise RuntimeError(f"{args[0]}: Command not found")
|
raise RuntimeError(f"{args[0]}: Command not found")
|
||||||
|
|
||||||
except KeyboardInterrupt:
|
except KeyboardInterrupt:
|
||||||
raise RuntimeError(f"{args[0]}: Interrupted")
|
raise RuntimeError(f"{cmdName}: Interrupted")
|
||||||
|
|
||||||
if proc.returncode == -signal.SIGSEGV:
|
if proc.returncode == -signal.SIGSEGV:
|
||||||
raise RuntimeError(f"{args[0]}: Segmentation fault")
|
raise RuntimeError(f"{cmdName}: Segmentation fault")
|
||||||
|
|
||||||
if proc.returncode != 0:
|
if proc.returncode != 0:
|
||||||
raise RuntimeError(f"{args[0]}: Process exited with code {proc.returncode}")
|
raise RuntimeError(f"{cmdName}: Process exited with code {proc.returncode}")
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
def popen(*args: str) -> str:
|
def popen(*args: str) -> str:
|
||||||
_logger.debug(f"Executing {args}")
|
_logger.debug(f"Executing {args}...")
|
||||||
|
|
||||||
|
cmdName = Path(args[0]).name
|
||||||
|
|
||||||
try:
|
try:
|
||||||
proc = subprocess.run(args, stdout=subprocess.PIPE, stderr=sys.stderr)
|
proc = subprocess.run(args, stdout=subprocess.PIPE, stderr=sys.stderr)
|
||||||
except FileNotFoundError:
|
except FileNotFoundError:
|
||||||
raise RuntimeError(f"{args[0]}: Command not found")
|
raise RuntimeError(f"{cmdName}: Command not found")
|
||||||
|
|
||||||
if proc.returncode == -signal.SIGSEGV:
|
if proc.returncode == -signal.SIGSEGV:
|
||||||
raise RuntimeError(f"{args[0]}: Segmentation fault")
|
raise RuntimeError(f"{cmdName}: Segmentation fault")
|
||||||
|
|
||||||
if proc.returncode != 0:
|
if proc.returncode != 0:
|
||||||
raise RuntimeError(f"{args[0]}: Process exited with code {proc.returncode}")
|
raise RuntimeError(f"{cmdName}: Process exited with code {proc.returncode}")
|
||||||
|
|
||||||
return proc.stdout.decode("utf-8").strip()
|
return proc.stdout.decode("utf-8").strip()
|
||||||
|
|
||||||
|
|
||||||
|
def debug(cmd: list[str], debugger: str = "lldb", wait: bool = False):
|
||||||
|
if debugger == "lldb":
|
||||||
|
exec(
|
||||||
|
"lldb",
|
||||||
|
*(("-o", "b main") if wait else ()),
|
||||||
|
*("-o", "run"),
|
||||||
|
*cmd,
|
||||||
|
)
|
||||||
|
elif debugger == "gdb":
|
||||||
|
exec(
|
||||||
|
"gdb",
|
||||||
|
*(("-ex", "b main") if wait else ()),
|
||||||
|
*("-ex", "run"),
|
||||||
|
*cmd,
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
raise RuntimeError(f"Unknown debugger {debugger}")
|
||||||
|
|
||||||
|
|
||||||
|
def profile(cmd: list[str]):
|
||||||
|
mkdir(const.TMP_DIR)
|
||||||
|
perfFile = f"{const.TMP_DIR}/perf.data"
|
||||||
|
try:
|
||||||
|
exec(
|
||||||
|
"perf",
|
||||||
|
"record",
|
||||||
|
"-g",
|
||||||
|
"-o",
|
||||||
|
perfFile,
|
||||||
|
"--call-graph",
|
||||||
|
"dwarf",
|
||||||
|
*cmd,
|
||||||
|
)
|
||||||
|
except Exception as e:
|
||||||
|
if not os.path.exists(perfFile):
|
||||||
|
raise e
|
||||||
|
|
||||||
|
try:
|
||||||
|
proc = subprocess.Popen(
|
||||||
|
["perf", "script", "-i", perfFile], stdout=subprocess.PIPE
|
||||||
|
)
|
||||||
|
subprocess.run(["speedscope", "-"], stdin=proc.stdout)
|
||||||
|
proc.wait()
|
||||||
|
except Exception as e:
|
||||||
|
rmrf(perfFile)
|
||||||
|
raise e
|
||||||
|
|
||||||
|
rmrf(perfFile)
|
||||||
|
|
||||||
|
|
||||||
def readdir(path: str) -> list[str]:
|
def readdir(path: str) -> list[str]:
|
||||||
_logger.debug(f"Reading directory {path}")
|
_logger.debug(f"Reading directory {path}")
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue