Skip to content

Commit eda584c

Browse files
committed
proc
Signed-off-by: Elazar Gershuni <elazarg@gmail.com>
1 parent 98889a3 commit eda584c

File tree

10 files changed

+518
-60
lines changed

10 files changed

+518
-60
lines changed

checkpoint/criu_binding.py

+113
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
from os import PathLike
2+
3+
from checkpoint.ctypes_modern import Clibrary
4+
import os
5+
6+
criu = Clibrary("criu")
7+
8+
9+
@criu.function
10+
def criu_init_opts() -> int: ...
11+
12+
13+
@criu.function
14+
def criu_check() -> int: ...
15+
16+
17+
@criu.function
18+
def criu_dump() -> int: ...
19+
20+
21+
@criu.function
22+
def criu_restore() -> int: ...
23+
24+
25+
@criu.function
26+
def criu_set_images_dir_fd(fd: int) -> None: ...
27+
28+
29+
@criu.function
30+
def criu_set_log_file(log_file: bytes) -> None: ...
31+
32+
33+
@criu.function
34+
def criu_set_log_level(log_level: int) -> None: ...
35+
36+
37+
@criu.function
38+
def criu_set_pid(pid: int) -> None: ...
39+
40+
41+
@criu.function
42+
def criu_set_leave_running(leave_running: bool) -> None: ...
43+
44+
45+
@criu.function
46+
def criu_set_service_address(address: bytes) -> None: ...
47+
48+
49+
@criu.function
50+
def criu_set_track_mem(track_mem: bool) -> None: ...
51+
52+
53+
@criu.function
54+
def criu_set_ext_unix_sk(ext_unix_sk: bool) -> None: ...
55+
56+
57+
@criu.function
58+
def criu_set_tcp_established(tcp_established: bool) -> None: ...
59+
60+
61+
@criu.function
62+
def criu_set_evasive_devices(evasive_devices: bool) -> None: ...
63+
64+
65+
@criu.function
66+
def criu_set_shell_job(shell_job: bool) -> None: ...
67+
68+
69+
@criu.function
70+
def criu_set_file_locks(file_locks: bool) -> None: ...
71+
72+
73+
@criu.function
74+
def criu_set_log_level(log_level: int) -> None: ...
75+
76+
77+
@criu.function
78+
def criu_set_log_file(log_file: bytes) -> None: ...
79+
80+
81+
def set_criu(folder: str | bytes | PathLike[str] | PathLike[bytes]) -> None:
82+
if criu_init_opts() < 0:
83+
raise OSError("CRIU init failed")
84+
85+
try:
86+
fd = os.open(folder, os.O_DIRECTORY)
87+
except OSError as e:
88+
raise OSError(f"Failed to open criu_images directory: {e}")
89+
criu_set_images_dir_fd(fd)
90+
91+
criu_set_log_file(b"criu.log")
92+
criu_set_log_level(4)
93+
criu_set_pid(os.getpid())
94+
criu_set_leave_running(True)
95+
criu_set_service_address(b"/tmp/criu_service.socket")
96+
criu_set_track_mem(False)
97+
98+
99+
if __name__ == "__main__":
100+
set_criu("../scripts/criu_images")
101+
c = criu_check()
102+
if c < 0:
103+
print(f"Failed to check CRIU: {os.strerror(c)}")
104+
elif c == 0:
105+
print("CRIU is available")
106+
else:
107+
print("CRIU is not available")
108+
109+
# Perform a checkpoint
110+
criu_dump()
111+
# move criu_images/pages-1.img to criu_images/pages_old.img
112+
os.rename("../scripts/criu_images/pages-1.img", "criu_images/pages_old.img")
113+
criu_dump()

checkpoint/ctypes_modern.py

+72
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
import ctypes
2+
from ctypes.util import find_library
3+
from typing import Any, Callable, Type, get_type_hints
4+
5+
6+
def _get_ctype(type_hint: Type) -> Any:
7+
if type_hint is int:
8+
return ctypes.c_int
9+
elif type_hint is float:
10+
return ctypes.c_float
11+
elif type_hint is bool:
12+
return ctypes.c_bool
13+
elif type_hint is bytes:
14+
return ctypes.c_char_p
15+
elif type_hint is None:
16+
return None
17+
else:
18+
raise TypeError(f"Unsupported type hint: {type_hint}")
19+
20+
21+
def structure[T](cls: Type[T]) -> Type:
22+
"""
23+
A decorator to create a ctypes Structure class using type hints.
24+
"""
25+
return type(
26+
cls.__name__,
27+
(ctypes.Structure,),
28+
{
29+
"_fields_": [
30+
(name, _get_ctype(type_hint))
31+
for name, type_hint in get_type_hints(cls).items()
32+
]
33+
},
34+
)
35+
36+
37+
class Clibrary:
38+
"""
39+
A class for wrapping C libraries and their functions.
40+
"""
41+
42+
def __init__(self, library_name: str):
43+
self.lib = ctypes.CDLL(find_library(library_name))
44+
45+
def function[
46+
*Args, Res
47+
](self, func: Callable[[*Args], Res]) -> Callable[[*Args], Res]:
48+
"""
49+
A decorator method for wrapping individual C functions.
50+
"""
51+
func_name = func.__name__
52+
annotations = func.__annotations__
53+
54+
c_func = getattr(self.lib, func_name)
55+
c_func.restype = _get_ctype(annotations.get("return"))
56+
c_func.argtypes = [
57+
_get_ctype(arg_type)
58+
for arg_name, arg_type in annotations.items()
59+
if arg_name != "return"
60+
]
61+
62+
return c_func
63+
64+
65+
criu = Clibrary("criu")
66+
67+
68+
@criu.function
69+
def criu_init_opts() -> int: ...
70+
71+
72+
criu_init_opts()

checkpoint/persist.py

+36-8
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
import hashlib
1111
import socket
1212
import struct
13-
13+
from checkpoint.criu_binding import set_criu, criu_dump
1414

1515
FUEL = "FUEL"
1616
STEP = "STEP"
@@ -59,10 +59,10 @@ def __init__(self, module_filename: str | pathlib.Path, env) -> None:
5959

6060
# make sure the cache is invalidated when the module changes
6161
h = compute_hash(module_filename, env)
62-
cachedir = pathlib.Path(tempfile.gettempdir()) / f"pythia-{h}"
63-
print(f"Using cache directory {cachedir}", file=sys.stderr)
64-
cachedir.mkdir(parents=False, exist_ok=True)
65-
self.filename = cachedir / "store.pickle"
62+
cache_dir = pathlib.Path(tempfile.gettempdir()) / f"pythia-{h}"
63+
print(f"Using cache directory {cache_dir}", file=sys.stderr)
64+
cache_dir.mkdir(parents=False, exist_ok=True)
65+
self.filename = cache_dir / "store.pickle"
6666
(results_path / tag).mkdir(parents=True, exist_ok=True)
6767
self.tsv_filename = (results_path / tag / module_filename.stem).with_suffix(
6868
".tsv"
@@ -243,6 +243,34 @@ def sigint() -> None:
243243
os.kill(PID, signal.SIGINT)
244244

245245

246-
def self_coredump(i) -> None:
247-
if i % STEP_VALUE in [0, 1]:
248-
sigint()
246+
SET_CRIU = False
247+
CRIU_FOLDER = pathlib.Path("criu_images")
248+
CRIU_DUMPS = CRIU_FOLDER / "dumps"
249+
250+
coredump_iterations = 0
251+
coredump_steps = 0
252+
253+
254+
def self_coredump() -> None:
255+
global coredump_iterations, coredump_steps
256+
if not coredump_iterations:
257+
CRIU_FOLDER.mkdir(exist_ok=True)
258+
shutil.rmtree(CRIU_DUMPS, ignore_errors=True)
259+
CRIU_DUMPS.mkdir(exist_ok=False)
260+
set_criu(CRIU_FOLDER)
261+
coredump_iterations += 1
262+
263+
if coredump_iterations % STEP_VALUE in [0, 1]:
264+
criu_dump()
265+
image_file = CRIU_FOLDER / "pages-1.img"
266+
if not image_file.exists():
267+
raise RuntimeError(
268+
"CRIU image was not created. Make sure to run the CRIU service:\n"
269+
"sudo criu service --shell-job --address /tmp/criu_service.socket"
270+
)
271+
target_image = CRIU_DUMPS / f"{coredump_steps:05d}.a.img"
272+
os.rename(CRIU_FOLDER / "pages-1.img", target_image)
273+
if coredump_steps > 0:
274+
source_image = CRIU_DUMPS / f"{coredump_steps-1:05d}.b.img"
275+
source_image.hardlink_to(target_image)
276+
coredump_steps += 1

experiment/k_means/proc.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from checkpoint.persist import self_coredump
1+
from checkpoint import persist
22
import numpy as np
33
import sklearn.datasets
44

@@ -21,7 +21,7 @@ def run(X: np.ndarray, k: int, max_iterations: int) -> np.ndarray:
2121
centroids = X[np.random.choice(nsamples, k)]
2222
clusters = list[list[int]]()
2323
for i in range(max_iterations): # type: int
24-
self_coredump(i)
24+
persist.self_coredump()
2525
clusters = [list[int]() for _ in range(k)]
2626
for sample_i in range(len(X)):
2727
r = np.argmin(np.linalg.norm(X[sample_i] - centroids, axis=1))

experiment/omp/proc.py

+87
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
from checkpoint import persist
2+
import sys
3+
import numpy as np
4+
import argparse
5+
6+
7+
def append_int(a: np.ndarray, n: int) -> np.ndarray:
8+
return np.append(a, n)
9+
10+
11+
def get_float(array: np.ndarray, idx: int) -> float:
12+
res = array[idx]
13+
return res
14+
15+
16+
def log(idx: int, k: int) -> None:
17+
print(f"{idx} / {k}", end="\r", flush=True, file=sys.stderr)
18+
19+
20+
def run(features: np.ndarray, target: np.ndarray, k: int) -> np.ndarray:
21+
"""select k features from features using target as the target variable"""
22+
S = np.array([], "int")
23+
for idx in range(k): # type: int
24+
persist.self_coredump()
25+
log(idx, k)
26+
dims = np.unique(S[S >= 0])
27+
target = np.array(target).reshape(target.shape[0], -1)
28+
X = features[:, dims]
29+
if X.size == 0:
30+
prediction = np.zeros(features.shape[0]).reshape(features.shape[0], -1)
31+
else:
32+
if X.ndim == 1:
33+
X = X.reshape(X.shape[0], 1)
34+
y = np.concatenate(target)
35+
X = (X - X.mean()) / X.std()
36+
X = np.c_[np.ones(X.shape[0]), X]
37+
theta = np.zeros(X.shape[1])
38+
for _ in range(10000):
39+
error = np.dot(X, theta.T) - y
40+
theta -= 0.1 * (1 / y.size) * np.dot(X.T, error)
41+
prediction = np.zeros((len(X), 1))
42+
for j in range(len(X)):
43+
total = 0.0
44+
xj = X[j, :]
45+
for i in range(len(xj)):
46+
x = get_float(xj, i)
47+
t = get_float(theta, i)
48+
total += x * t
49+
prediction[j] = total
50+
grad = np.dot(features.T, target - prediction)
51+
points = np.setdiff1d(np.array(range(len(grad))), S).astype("int")
52+
if len(points) == 0:
53+
break
54+
a = points[0]
55+
m = get_float(grad, a)
56+
for i in range(len(points)):
57+
p = points[i]
58+
n = get_float(grad, p)
59+
if n > m:
60+
a = p
61+
m = n
62+
if m >= 0:
63+
S = np.unique(append_int(S, a))
64+
else:
65+
break
66+
return S
67+
68+
69+
def main(dataset: str, k: int) -> None:
70+
features = np.load(f"experiment/omp/{dataset}_features.npy")
71+
target = np.load(f"experiment/omp/{dataset}_target.npy")
72+
S = run(features, target, k)
73+
print(S)
74+
75+
76+
if __name__ == "__main__":
77+
parser = argparse.ArgumentParser()
78+
parser.add_argument(
79+
"dataset",
80+
choices=["dataset_20KB", "dataset_large", "healthstudy"],
81+
help="dataset to use",
82+
)
83+
parser.add_argument(
84+
"--k", type=int, default=100000, help="number of features to select"
85+
)
86+
args = parser.parse_args()
87+
main(args.dataset, args.k)

0 commit comments

Comments
 (0)