From 0b31a50c20c1054edf3377d2c920481e48e7cd6c Mon Sep 17 00:00:00 2001 From: pajjilykk Date: Wed, 13 May 2026 08:54:08 +0700 Subject: [PATCH] add 13 comp --- 13comp/Makefile | 25 +++ 13comp/exporter.py | 168 +++++++++++++++++++ 13comp/pipe_sort | Bin 0 -> 38712 bytes 13comp/pipe_sort.cpp | 377 +++++++++++++++++++++++++++++++++++++++++++ 13comp/shm_sort | Bin 0 -> 33560 bytes 13comp/shm_sort.cpp | 295 +++++++++++++++++++++++++++++++++ 6 files changed, 865 insertions(+) create mode 100644 13comp/Makefile create mode 100644 13comp/exporter.py create mode 100755 13comp/pipe_sort create mode 100644 13comp/pipe_sort.cpp create mode 100755 13comp/shm_sort create mode 100644 13comp/shm_sort.cpp diff --git a/13comp/Makefile b/13comp/Makefile new file mode 100644 index 0000000..1ec5d82 --- /dev/null +++ b/13comp/Makefile @@ -0,0 +1,25 @@ +CXX := g++ +CXXFLAGS := -O2 -std=c++17 -Wall -Wextra -pedantic +PYTHON := $(abspath ../.venv/bin/python) +OUT_DIR := out + +.PHONY: all run test export clean + +all: shm_sort pipe_sort + +shm_sort: shm_sort.cpp + $(CXX) $(CXXFLAGS) shm_sort.cpp -o shm_sort + +pipe_sort: pipe_sort.cpp + $(CXX) $(CXXFLAGS) pipe_sort.cpp -o pipe_sort + +run: all + $(PYTHON) exporter.py --out $(OUT_DIR) + +test: run + +export: run + +clean: + rm -f shm_sort pipe_sort + rm -rf $(OUT_DIR) __pycache__ diff --git a/13comp/exporter.py b/13comp/exporter.py new file mode 100644 index 0000000..ee3d8b8 --- /dev/null +++ b/13comp/exporter.py @@ -0,0 +1,168 @@ +#!/usr/bin/env python3 +from __future__ import annotations + +import argparse +import csv +import os +import re +import subprocess +from pathlib import Path + +os.environ.setdefault("MPLCONFIGDIR", str(Path("out") / ".matplotlib")) + +import matplotlib + +matplotlib.use("Agg") +import matplotlib.pyplot as plt + +STAT_RE = re.compile( + r"STAT: program=(\w+) size=(\d+) depth=(\d+) min_size=(\d+) valid=(\d+) time=([\d.eE+-]+)" +) + + +def seed_for(size: int, repeat: int) -> int: + return 13013 + size * 17 + repeat * 1_000_003 + + +def run_once(binary: str, program: str, size: int, depth: int, min_size: int, seed: int) -> dict: + cmd = [ + binary, + "--size", + str(size), + "--depth", + str(depth), + "--min-size", + str(min_size), + "--seed", + str(seed), + ] + + proc = subprocess.run(cmd, stdout=subprocess.DEVNULL, stderr=subprocess.PIPE, text=True) + + if proc.returncode != 0: + raise RuntimeError("Command failed: " + " ".join(cmd) + "\n" + proc.stderr) + + match = STAT_RE.search(proc.stderr) + if not match: + raise RuntimeError("STAT line not found: " + proc.stderr) + + stat_program, stat_size, stat_depth, stat_min_size, valid, elapsed = match.groups() + + if stat_program != program: + raise RuntimeError(f"expected program={program}, got {stat_program}") + if valid != "1": + raise RuntimeError("sort validation failed: " + proc.stderr) + + return { + "program": program, + "size": int(stat_size), + "depth": int(stat_depth), + "min_size": int(stat_min_size), + "seed": seed, + "time": float(elapsed), + } + + +def write_csv(path: Path, rows: list[dict]) -> None: + path.parent.mkdir(parents=True, exist_ok=True) + header = ["program", "size", "depth", "min_size", "seed", "time"] + + with path.open("w", encoding="utf-8", newline="") as f: + writer = csv.DictWriter(f, fieldnames=header) + writer.writeheader() + writer.writerows(rows) + + +def draw_graph(path: Path, rows: list[dict]) -> None: + path.parent.mkdir(parents=True, exist_ok=True) + + sizes = sorted({row["size"] for row in rows}) + programs = ["shm", "pipe"] + markers = {"shm": "o", "pipe": "s"} + labels = {"shm": "Разделяемая память", "pipe": "Каналы"} + + fig, (time_ax, speed_ax) = plt.subplots(1, 2, figsize=(15, 6)) + + for program in programs: + cur = [row for row in rows if row["program"] == program] + cur.sort(key=lambda row: row["size"]) + time_ax.plot( + [row["size"] for row in cur], + [row["time"] for row in cur], + marker=markers[program], + label=labels[program], + ) + + for program in programs: + cur = [row for row in rows if row["program"] == program] + cur.sort(key=lambda row: row["size"]) + speed_ax.plot( + [row["size"] for row in cur], + [row["size"] / row["time"] if row["time"] > 0 else 0 for row in cur], + marker=markers[program], + label=labels[program], + ) + + time_ax.set_xscale("log", base=2) + speed_ax.set_xscale("log", base=2) + + time_ax.set_xlabel("Размер списка") + time_ax.set_ylabel("Время, секунды") + time_ax.set_title("Время сортировки связного списка слиянием") + time_ax.grid(True) + time_ax.legend() + + speed_ax.set_xlabel("Размер списка") + speed_ax.set_ylabel("Элементов в секунду") + speed_ax.set_title("Скорость сортировки на одинаковых нагрузках") + speed_ax.grid(True) + speed_ax.legend() + + fig.suptitle("Разделяемая память и каналы: задача сортировки списка из лабораторной 1") + fig.tight_layout() + fig.savefig(path, dpi=150) + plt.close(fig) + + +def main() -> None: + parser = argparse.ArgumentParser() + parser.add_argument("--out", default="out", help="output directory") + parser.add_argument("--depth", type=int, default=3) + parser.add_argument("--min-size", type=int, default=4096) + parser.add_argument("--repeats", type=int, default=3) + parser.add_argument( + "--sizes", + type=int, + nargs="+", + default=[2**power for power in range(9, 19)], + ) + args = parser.parse_args() + + out_dir = Path(args.out) + rows = [] + + for size in args.sizes: + for program, binary in [("shm", "./shm_sort"), ("pipe", "./pipe_sort")]: + measurements = [] + + for repeat in range(args.repeats): + seed = seed_for(size, repeat) + row = run_once(binary, program, size, args.depth, args.min_size, seed) + measurements.append(row) + print( + f"{program}: size={size} repeat={repeat + 1}/{args.repeats} " + f"time={row['time']:.6f}", + flush=True, + ) + + best = min(measurements, key=lambda row: row["time"]) + rows.append(best) + + write_csv(out_dir / "benchmark.csv", rows) + draw_graph(out_dir / "speed_comparison.png", rows) + print(f"Saved {out_dir / 'benchmark.csv'}") + print(f"Saved {out_dir / 'speed_comparison.png'}") + + +if __name__ == "__main__": + main() diff --git a/13comp/pipe_sort b/13comp/pipe_sort new file mode 100755 index 0000000000000000000000000000000000000000..3c0282b6ee8d828623f8977b93baddb092e6031f GIT binary patch literal 38712 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 literal 0 HcmV?d00001 diff --git a/13comp/pipe_sort.cpp b/13comp/pipe_sort.cpp new file mode 100644 index 0000000..0c11509 --- /dev/null +++ b/13comp/pipe_sort.cpp @@ -0,0 +1,377 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +constexpr int NIL = -1; + +struct Node { + int32_t value; + int next; +}; + +struct Options { + size_t size = 100000; + int max_depth = 3; + size_t min_size = 4096; + unsigned seed = 1337; + bool print = false; +}; + +struct SortResult { + std::vector values; +}; + +static void throw_errno(const std::string& what) { + throw std::runtime_error(what + ": " + std::strerror(errno)); +} + +static void close_checked(int fd) { + if (fd >= 0) { + while (close(fd) < 0 && errno == EINTR) {} + } +} + +static void write_all(int fd, const void* data, size_t bytes) { + const char* p = static_cast(data); + + while (bytes > 0) { + ssize_t n = write(fd, p, bytes); + if (n < 0) { + if (errno == EINTR) continue; + throw_errno("write"); + } + if (n == 0) throw std::runtime_error("write returned zero"); + p += n; + bytes -= static_cast(n); + } +} + +static void read_all(int fd, void* data, size_t bytes) { + char* p = static_cast(data); + + while (bytes > 0) { + ssize_t n = read(fd, p, bytes); + if (n < 0) { + if (errno == EINTR) continue; + throw_errno("read"); + } + if (n == 0) throw std::runtime_error("unexpected EOF"); + p += n; + bytes -= static_cast(n); + } +} + +static void send_values(int fd, const std::vector& values) { + uint64_t n = static_cast(values.size()); + write_all(fd, &n, sizeof(n)); + if (!values.empty()) write_all(fd, values.data(), values.size() * sizeof(values[0])); +} + +static std::vector recv_values(int fd) { + uint64_t n = 0; + read_all(fd, &n, sizeof(n)); + + if (n > static_cast(SIZE_MAX / sizeof(int32_t))) { + throw std::runtime_error("input too large"); + } + + std::vector values(static_cast(n)); + if (!values.empty()) read_all(fd, values.data(), values.size() * sizeof(values[0])); + return values; +} + +static int merge_lists(std::vector& nodes, int left, int right) { + if (left == NIL) return right; + if (right == NIL) return left; + + int head = NIL; + int tail = NIL; + + auto append = [&](int idx) { + if (head == NIL) { + head = idx; + tail = idx; + } else { + nodes[tail].next = idx; + tail = idx; + } + }; + + while (left != NIL && right != NIL) { + if (nodes[left].value <= nodes[right].value) { + int next = nodes[left].next; + append(left); + left = next; + } else { + int next = nodes[right].next; + append(right); + right = next; + } + } + + if (left != NIL) nodes[tail].next = left; + if (right != NIL) nodes[tail].next = right; + return head; +} + +static void split_list(std::vector& nodes, int head, int& left, int& right) { + if (head == NIL || nodes[head].next == NIL) { + left = head; + right = NIL; + return; + } + + int slow = head; + int fast = nodes[head].next; + + while (fast != NIL) { + fast = nodes[fast].next; + if (fast != NIL) { + slow = nodes[slow].next; + fast = nodes[fast].next; + } + } + + left = head; + right = nodes[slow].next; + nodes[slow].next = NIL; +} + +static int local_sort(std::vector& nodes, int head) { + if (head == NIL || nodes[head].next == NIL) return head; + + int left = NIL; + int right = NIL; + split_list(nodes, head, left, right); + left = local_sort(nodes, left); + right = local_sort(nodes, right); + return merge_lists(nodes, left, right); +} + +static std::vector make_nodes(const std::vector& values) { + std::vector nodes(values.size()); + + for (size_t i = 0; i < values.size(); ++i) { + nodes[i].value = values[i]; + nodes[i].next = (i + 1 == values.size()) ? NIL : static_cast(i + 1); + } + + return nodes; +} + +static std::vector collect_values(const std::vector& nodes, int head) { + std::vector out; + out.reserve(nodes.size()); + + for (int cur = head; cur != NIL; cur = nodes[cur].next) { + out.push_back(nodes[cur].value); + } + + return out; +} + +static std::vector sort_values_as_list(std::vector values) { + if (values.size() < 2) return values; + + std::vector nodes = make_nodes(values); + int head = local_sort(nodes, 0); + return collect_values(nodes, head); +} + +static void split_values_as_list(const std::vector& values, + std::vector& left_values, + std::vector& right_values) { + std::vector nodes = make_nodes(values); + + int left = NIL; + int right = NIL; + split_list(nodes, values.empty() ? NIL : 0, left, right); + + left_values = collect_values(nodes, left); + right_values = collect_values(nodes, right); +} + +static std::vector merge_values_as_list(const std::vector& left_values, + const std::vector& right_values) { + std::vector nodes; + nodes.reserve(left_values.size() + right_values.size()); + + int left = NIL; + int left_tail = NIL; + for (int32_t value : left_values) { + int idx = static_cast(nodes.size()); + nodes.push_back({value, NIL}); + if (left == NIL) left = idx; + else nodes[left_tail].next = idx; + left_tail = idx; + } + + int right = NIL; + int right_tail = NIL; + for (int32_t value : right_values) { + int idx = static_cast(nodes.size()); + nodes.push_back({value, NIL}); + if (right == NIL) right = idx; + else nodes[right_tail].next = idx; + right_tail = idx; + } + + int head = merge_lists(nodes, left, right); + return collect_values(nodes, head); +} + +static SortResult parallel_sort(std::vector values, int depth, const Options& opt); + +static pid_t spawn_child(const std::vector& part, + int depth, + const Options& opt, + int& result_fd) { + int to_child[2] = {-1, -1}; + int from_child[2] = {-1, -1}; + + if (pipe(to_child) < 0) throw_errno("pipe to_child"); + if (pipe(from_child) < 0) throw_errno("pipe from_child"); + + pid_t pid = fork(); + if (pid < 0) throw_errno("fork"); + + if (pid == 0) { + try { + close_checked(to_child[1]); + close_checked(from_child[0]); + + std::vector input = recv_values(to_child[0]); + close_checked(to_child[0]); + + SortResult result = parallel_sort(std::move(input), depth, opt); + send_values(from_child[1], result.values); + close_checked(from_child[1]); + _exit(0); + } catch (...) { + _exit(2); + } + } + + close_checked(to_child[0]); + close_checked(from_child[1]); + send_values(to_child[1], part); + close_checked(to_child[1]); + + result_fd = from_child[0]; + return pid; +} + +static SortResult parallel_sort(std::vector values, int depth, const Options& opt) { + if (values.size() < 2 || depth >= opt.max_depth || values.size() <= opt.min_size) { + return {sort_values_as_list(std::move(values))}; + } + + std::vector left; + std::vector right; + split_values_as_list(values, left, right); + + int left_fd = -1; + int right_fd = -1; + pid_t left_pid = spawn_child(left, depth + 1, opt, left_fd); + pid_t right_pid = spawn_child(right, depth + 1, opt, right_fd); + + std::vector sorted_left = recv_values(left_fd); + std::vector sorted_right = recv_values(right_fd); + close_checked(left_fd); + close_checked(right_fd); + + int left_status = 0; + int right_status = 0; + while (waitpid(left_pid, &left_status, 0) < 0 && errno == EINTR) {} + while (waitpid(right_pid, &right_status, 0) < 0 && errno == EINTR) {} + + if (!WIFEXITED(left_status) || WEXITSTATUS(left_status) != 0) { + throw std::runtime_error("left child failed"); + } + if (!WIFEXITED(right_status) || WEXITSTATUS(right_status) != 0) { + throw std::runtime_error("right child failed"); + } + + return {merge_values_as_list(sorted_left, sorted_right)}; +} + +static Options parse_args(int argc, char** argv) { + Options opt; + + for (int i = 1; i < argc; ++i) { + std::string s = argv[i]; + + auto value = [&](const std::string& name) -> std::string { + if (i + 1 >= argc) throw std::runtime_error("missing value for " + name); + return argv[++i]; + }; + + if (s == "--size" || s == "-n") { + opt.size = std::stoull(value(s)); + } else if (s == "--depth" || s == "-d") { + opt.max_depth = std::stoi(value(s)); + } else if (s == "--min-size" || s == "-m") { + opt.min_size = std::stoull(value(s)); + } else if (s == "--seed") { + opt.seed = static_cast(std::stoul(value(s))); + } else if (s == "--print") { + opt.print = true; + } else if (s == "--help" || s == "-h") { + std::cout << "Usage: ./pipe_sort [--size N] [--depth D] [--min-size M] " + << "[--seed S] [--print]\n"; + std::exit(0); + } else { + throw std::runtime_error("unknown argument: " + s); + } + } + + if (opt.max_depth < 0) throw std::runtime_error("depth must be non-negative"); + if (opt.size == 0) throw std::runtime_error("size must be positive"); + return opt; +} + +int main(int argc, char** argv) { + try { + Options opt = parse_args(argc, argv); + std::vector values(opt.size); + + std::mt19937 rng(opt.seed); + std::uniform_int_distribution dist(-100000000, 100000000); + + for (int32_t& value : values) value = dist(rng); + + const auto t1 = std::chrono::steady_clock::now(); + SortResult result = parallel_sort(std::move(values), 0, opt); + const auto t2 = std::chrono::steady_clock::now(); + + const double elapsed = std::chrono::duration(t2 - t1).count(); + const bool ok = std::is_sorted(result.values.begin(), result.values.end()) && + result.values.size() == opt.size; + + if (opt.print) { + for (int32_t value : result.values) std::cout << value << ' '; + std::cout << '\n'; + } + + std::cerr << "STAT: program=pipe size=" << opt.size + << " depth=" << opt.max_depth + << " min_size=" << opt.min_size + << " valid=" << (ok ? 1 : 0) + << " time=" << elapsed << " sec\n"; + + return ok ? 0 : 3; + } catch (const std::exception& e) { + std::cerr << "ERROR: " << e.what() << "\n"; + return 1; + } +} diff --git a/13comp/shm_sort b/13comp/shm_sort new file mode 100755 index 0000000000000000000000000000000000000000..e9d778bd1c7fc904a39e01ea66404b15876b1709 GIT binary patch literal 33560 zcmeHw4SZD9weOi^h74bsfPkr58R=l7Ld+x~Bp@{dGk8V@j3ihtqC=QW$Y?&s%mjng z8cc#5hf!+1YSs49-qz=9?G?2}#IHaws1FdaDAlTH{WxP(P^+Y<%>A!@_MV&!b9^oL z{eG{%_siDI+H38#*IIk+@3RkQ-{|qp&oY@L5wfKpNQ7-J*C>@d;ox;V0#GTHOE&zT zCE2ABz|D-NrB`YIsalY;he9i-6PfZo$kWr|8Jtf*VIe`vXB5Jdv=jlQJPoIO7K+;G z2f@yMQ_$nkZ~^uCn7%5`p9UY`1rku7k9-rpLdzF!8Vaqv5Hc}Q;C5yqN~F7azPouo z0rQ9fK|tY85=VdQxj)mPgEAoqNW2sX(x1GPuoGb=qf(t~;RJm=-}*FY=llW+ebw(p z>rO^r70-9@QcZ9=ypQV>Q0S}S`J~G@LmJ$`$pVVXP#tLo3Tl&u^@o-WY0b zYoFd;UN*g~v@p_ASj_U3Auq|(?9M~~JVPQH1?tX@rZMv#{Y%M#iFc2g$A}qzmcxMY z8R(ay^JJp$gW;Lzb&!#Xeu{ydY4A%X{%Qld8FHp%u=9X{J>N6X+if6!zJdMc8pw&j z@tN#D!+`&J1O8y1{_{nE`#Sfjt)+&{rDJ8w}dXHUqzXVc_S-4eZP{kpHm( z|GNhKP6PXYVPMZM4dg#+Krc3+_ZrAQ&7gia8_;(f`12zJy;TPELk9L-WI*3xpqIuu zJO0wc?FM=`8Pv-Q2K@gEg2$x`2M+gS)H}_9-f!T~zZmHK5&SR?o$-it-b#$iRA82oP zI-SKUYa^im6t;$%S9t@~QKvJ|P}}N{w$_HC5pTd#U5g)2g@2*HHXIH%*LfhL2|{YT z)zOMzdmtE&hFY3IsB5fRO$m#tTN)#tkfz63(%RM>4K)Qd{qvlj#S2bCy+@Pw&ssgR zH5duDt`2&*T~vxtGe}WylgG2Tx}^p#J{fnQ9G6s=YMEPfQtJk#q6$hy6@;2s*EWXg z{I#vC+M0sR(UY!*vcWnq@-LH(%B|I^A1#XFE75|Q{ejwOpaB`F?$T-o)aqzy0Ih`Q zsBLU)0Y55ESI4NjvH)6Db4!W;vSMd38f9(W8h-$+SC=%mTl)u!z0l({?$bp3*vTiQO+{IzXh!`SlcA3E<+>8h=fZ-&0-YuUb%D;%{VXT1vugQ4jTj>S$wxypYz~GYJaRK+Ft?`ET@{016Nd zdKNcnE%Bf3f6gK_-MUaD+!6_L&y)sQ+M=4fQ+*v2e@nf;wYGUxaIhhu*QTl-MXnId zvaw|qy8ht6z*I78!Dx)dTx z3rmWJpw0?u-qNM6xn94su%xhJNSZ!rNJ6nwk75$Z!Wups`vCg0uy{5gQHhp?Recul z9K@{*9|?REsFXfh8iPOL8VhU$%V7aG<(H&fE`eq$;>}|J5k~W>NxBJZBr&g7oxNr> z<+uklE!`q*to<{iGfxBSxSn1E47Gn4qN#*#OmmY$BBc-DpS8hB9{3tQ3qB6Yv(A7w> zNaHzv4a;wqzRU6GIk#hrmnBUDPC@L;#lCM-g+_1Z^Sz)~arz2A-wV3HA866?kyw#N zl+8Li?e9d`s-vGKh=4sh`dK>qb2|ET9etmUUaX@Z)X__H^agG}EpMDUdRRw4S4S7? z9ynE+si$*(qSM||1hIZ1y4ZWNw6MmJ1HhM7j9}H#sjZ5Tr=w#DnF{$jI+kFmVAs(} zw+IC~ITB=L`O%%Oob{PeN2ifNlSHfbevRJp`+)f zsFKv6quX@!u#TRmqqpnm<8<^69bLaqU9Y2`qT}DFqfgY)@7B>L>FAqu^iy^82Xu6? zcBbUbI{J5X{9ASO({=P79bG&Vq~zyx^zZ8U_vz?o>gWe`^vOE*(j{=mk1D?Uh6*($NbA z5wKiGKVL_$)X|G{bXi9))zPbT^cgz(aCF!M!yXv+z_15~JuvKnVGj&@;Qy@$KDV8D zOz!;1D#t9_FTr-EyC<5J+$VSLwDvN?k~3ZaIXQJVer=O05hJ{T(h`S~2vc_uPFuRf zK89~2oVId_9)>?cIBnq)n;HIF!fET4*u?N(5l&mS#72hSLpW{K5*-Y`op4$c$pCsr{0CcEm(mMCKQRfN-)EMaH(O2TO?mdIoHGQw#K zmXH{}m~b26M~;Iq^_MS5l&mIL=VG@38$@9Vl%_fC7d1wBsMX8 z3gNWHN^E5KX@t|(D$&94@r2WsDiLP*D8gwgl~}>>EW&9Em8fF)u|>e?kwT)9;hzys zTd715!#^aPwonN>!`~sCwoZvWhQCHQZJ81h!}k+TTcyO2Z>an)5N;>@5W{y6PLC=Q z`xw5BaM~&*dKmr);j~3cY-adx33m{_iQ&H@oVH4djSRnsaM~gzIv9RC;j}eMgc*Jd z;j|@6tYG*}gws|iQN{4<2&YFFiAvyr-x}ntR7ivy*6_8QLzEV-sgDU~0aW0g&@u;!=9G%rk-XXLHo5 z7O=F#>PAvEL{ikEzD`8=t(P(FQlI!rV_G_>Zs{{rCbgD0U~`fBDi@^VDJ2;m{tZm$|8wd`OW9u3Z zu7rzPU#!bv#Yi;hsWE8!b5Uk>B1}{}Sdr6sY~7u#fy_CL_&$aeS}`Nc9-pH@j@39; zz;|X8n6H&wsdHD>3WKO%N&e<1KYOXX^YW8MRW~o&~|4?vHIsHxo7Emna14;}{x= zdVn!ME630)-bz+soH;Bjed^Ohj?Xxbk%8L8LqOGAP?)W3KCZMO=M!9wazKt<@35<{ zGh9uqB!f<905Ie&wH*@FPVhPRJHK?pvWpN;Ttyks5zfuzthQpxcp+uHm=r)2Y=j36 zs8<1}I@>=0A?=zF(EIyUJ8{Ol92-&IzAnd|04RpmTy|+>Ix?z9{0<}qqcURa5u??? ziMBiC_>+zfB&j>eM5f)@oQdzGE4lPD*6bP`(7C1^U}&2v-h{XiWct>0sU z4*(}Mf26#Mn%K<-lC+lCb{?9+i)W)?S5l@ERE$INW=g&gQq&jd=h;lQ*t%y^Z;H>k zjhM%0lyw8S$gbXms?o}M@0X-f*SD@h=1hI-RVI)3>-U&`a`x4kENMF(Ua9afuN<4J z_33xW?y>Y^#gC@^%yi`sP0g%)nO=DVQ%TA{VfoYDIRna{L|vdtZs5v;EK52gIktp+ zH3D+fYv`vDKZ)<6mJ&1YqgmPhMVgC78d&)UriHs`2eXZ=lvylYIW?R~nw77*G#5QX z7JLY8iF+}SB_3s?S$aMi!+#6|)JwsrK8YXA%Kd+XmGK#evGn2%wu30?t%;BCv5EK0 zV;;Jk>Ha{SN4lF?Nz*kJLgNJxt3E>lm0quMfOR{wTM24i&Zm5=t|YtLY2YrP*q;$g ze9FdBG&ryFC+Y@2K#ET}l-N%LiHWhHjP-@K$zABzk~A0-6xR=3m+@uN+K=)vnJHMv z)X6b3TWQc}LNgo|JiFYE%1!G`5=CU%j!>kE&I~ECw8A1uok^4J)`HPgY`0^DS2_9w z4Wl$`*?m~yglYfd3-tSxsAI(?F~{MB-S67EUPsHLPF?*umEG+qr*&NCfX#OE&nR=} zfT=CwvTZRtupGOF>0+Cu^=?O)bv0B;E>_3t=Pg!()JytMom0rdUFsizI+N1>X<-mzjE459A!3anKtK1(Lax^FO+cJ`VouwJ#@ItC?N5c3_z`n1c@!MGn} z69buospLV8*!{e%>qhG9%8Rn%bL6Xk`IM|fjC{`gkFm*i^KDjUgUQylnqs7G8%4Bo z+`)vowvtuO=jGU(EtSl?y0hRfDqu|GpyosKjk+59J2|G!E~KPNt~eZ>NbQ0856xe4 zJZw@gM9IjpD|{74qq(Fk%;?_-U6k~;Z5TI@LN={`n9Y@FnS^!Kuv#vCR)RI#I^a)K z=yH_Lr94Z_FQMEtBcrzGlOop6lD4i&6l@#id75@R)EIJ*36-_6|GRV z$x{7bKcY2CXP;HxuAV77_sOB2ppw%VpJ0_cx0__;vH^MR-@~ZmwpV?zD9pqJOs^>u zX<_%5(Pg5xoUgl{L1nWZkhf7UpJv=`(%WBHo|Yz$I;Kv;nndY(gUprT61OtotN5JB zwt0Gy@b!fl>MA~O-K8$3nvMG$l^$mg6&p()FUs}=DoqX?R7;TTgC8qxTdsF3r%JJQ zeg$u|=1^t)krbe61HJWPq|h0qi^}l{eXOj3x#rFRi%q}ce134J%b>v4XWSPWFF zXH@Ij3#U(yglt_i;n!_w<Qx;})55Non^kEg*t56;7K7E}uPr)@cg+X;^KcktokL#;>8*?)l~4R(3n!Q(T+-$gdzpIh-9 zNZ-#Z(a&w&`7k`;zz@0(I%@QHXo?9p)UCZS8!t~b*t%B%N!9xYaMwRr@7J+@%!jgZ zRHPG!vX#7Cw(d&AY+J?+mW;Ikt)hSJ=zzCb&8JGU;v*7>x@L6@ufbO_$+gP^PV_>o ziPb%55Wd-URO9p}xhu9r>O6)jrzOqfVCs-f+vV*EyREw(ltQuN7O$tTWRXyV{gKP7E-^F4X4!a>Vmee z4Iphp|E7NT5*}&EnC$b^M8DSge$Uo`pkT^dZo&|3>s~`P-GraiD8L5V?T~{yWbW(t zFnd{?l#$VxSqgkgAM>Vq9cyVrji-SppXv%vJyOMxmAzUHt0)U+)7o018d|*-&$(=O z^i_6Yq`4Ob@x`Yen~iDt`(l*ZhB`*^qK=s~kmr)5zH#~L z7AovayBu4r%AMEe)0eg0cDQF7J$xjOmOtzid^O@~R%PpvgdfE2lUUdb_ zMbkuljvHL+Gq6C^*Y7B|woxhvADX31n!ZL{tPVB~vP|Tns)(muC+6Bgo=-tWSO1b& z{zzi@h`fA|WiMD@TXQe*xQNH1mE}T>NBun*&=S<&AWiIc|Bd8!95;QZr}I!YHAnu8 zWCB}K+PX{0U2AvJVpBZ4bNPFpro{xQc}+!|dj@rlA)1fQi7vMA*Y$|0RKD~c!TSD? z_M|?QfUx3GrWBBnYM-!VddZ_;8BHcrXvWvls|VBjDE&X_=O#=ObY9{7*sHvBrL4RocfNb1 zs)p7F&!fqGisa0SVrKS^uM$;9&gZ4sBrG9-z@)E1SJIFE^!+hjb z_H`alMrAqBCkI}U1MXe4jER;RMZ2TzfB1JPr+N>H9P>R$}1z=x){^mOC1B+f?j8ojq`~t&2UPQ5tFc z^_6nKt2|Fn{M%8z&i%gl|DwL18W{YHWgsUQCz42P~ z4v+JBwv%;rUcb`}6+IZhFjDyxv%`mCSk+yy&=)g1{}faVtGE>(OKGF?=-q0k#4%&Kw#rBvQ#}!Hxdlt++HV(n)@Ikl*c0pSBuxLoeLV zPTv3>tQtx&P`F{jytrG+!iHx~5*r2EZL^rE+6Km_jDfvRvSpom$6v|hF^=vYm(pij z|6^F;ihGg}?dkr~)>Q(W%7*7pj1e*7++|yzfJ9r@L->X60xBaQdoxa3trWO%uv7Lf zTT-lF1U8L4&8;NW$(%eHsc6_dag6c`&0t$8eFr2d zZ=&h&mcpcJ%|*p(erR(Uv^lYp?Fc0GuWw^3RBpC)zYIeXk1?y!F4X@m=)Weqc9cY| zj#{}-(OQU45jDJkgyV>4bN$l(=$i8C=&Y!vm0;j93?+J_Or?hAY;j!$F;xV5ub^#lOeAox%d$8nfev90T2dpSCcDL}- zF4imD$}v|GqxN=cCwX#(8oe}j3N|{?84J5Vj^@bcs9u~7V0)A8R=$@uluscWW#u{D zT5l*v^epwVL(mJ+x*4FKHWOC$L0Hs})i%X9fva=2#Ff-AZf#N7_7pAHC3Fpb;7e23 zG(LqjVhW45ph)M-G_>7=5^3kpIE_~S@+Q?T6$*vJKKR-nusv{*wg;}p_5dqhI*U#- zZxu~YR3tuL(`xAD{&O}m@6i_ME%r!7y`Gf}lLSt->4_8bpF#)SIDmQqC&%h($-6`s&4aKxgV-qgubHmScV>IjWAL5>@oF=_hJsCStr} zCt7m%>(NiVu?ujL{hF+Nq8@%DnY{c84D8Eocl4kcL7p#`BP+*z@!Rt0Igs*q+Q!9P z^f=2ZuYDh`>+mT(Q5+ErvK4HI>O5xerfbgq#oMlDl-KA&F(z%8Sl`jVO~M&uPJk zbL~PoUS*PFW~|@uBH^fLEP-~&+dmww?3bN8=!xIa@VcR$xaUZACJ(R)UtQrO_6Zn}=xaCt zkziny_QLaFia*lQ8l^I_0xV+1)r#q6aiP(^@CrN6&OmU_9+&C#?AiALqko7X z?@cE60T#TJOpd{$%Y}e+eElpSJq!L~e=_+IwvLWJC6iy{F^u|JGWh`DK|F|}ZMceu zngb*UPde9we*o}4z`Jpt6Ggt~a6;M+{^xK=a|HCQILxU8{Q(@}gG#c%Y_zx3Cm2yazTzwv?MUKR5qk z+vsbp9nyuT%|5rpF@^Yuc{%=6{Fn(@s-mO`l-28a<++6zxvpct7oyDD7)Hx!{H!8Qlm201y zn-8A3xmFk6BxCk`1h^IU{2q{koqkZ(8u*p!NOI-ob!I_G*3F}+SXR$yX&T6z@b}G& z$z&0D&4*EF$c<+~{)TMmS!Z_T7IZ>)2a+Wp{-}=k;Z*ntp!sq$-$h|{vm9>D0h=-X=l!&bt5j>V9BcQ^X$G3%pk5C zvBA<3H-~S{zAY>3eErVZ?lO-|jtoUtBpzutV=| z=%so(AJBXX^g=^t&L9u99crr^QJw{eYvplMdE8W@%OhYF{9`wP-!9LRpAr4`BXtOcExh3m|hZ^&M=d*O!c zEcfnZ;72t}Rp40<{_kYLMH_uJgn~Uo0qTGE2*-fKRbEwM`Yfful zWP=_4cwhu%-V2$?r1uAzM&X?|vn|=u0KUkgy;e=_odVUr`2{?ZLdZj$PPYZV8M5h} zfG9n(LSX$AILHXu__S#jHE%@o@Ohg2EPN;pBC@UcLJgpCS~6*}mY;?38jmaypX5Jp zgGsv6WI1kn9lsJrA@jJNtauCP15})%ljtjX%o(Xlq}1w+$>Fg$h3UGG@CeyD?r&$u&*>f##WSQD58%Jc{ zWU|CYWIt{q>Zc~lQFHcjljSvY_8+qfK>2O29Jyy%wvDvR#Enknxj*ldfFO0N2H7fhnk(RBavTqsX z0OiOi%QK_1zZqrOHadIr=n_zpqb>h2Hv7RbBy-;wlE$nqC!3R|(cYU)J55r*3EpG@ z-JP`=!s+{^SshXj(S-l;ogs$fZ2}hH?jh;KOYMyKDL)0G(cf?w_Q0?QhCT5Ag9pU- z#l-i-jLIa&P5L$(1%bDx;q>h`eL8)sjlviWNRnNP;Kf!J%H0~oFwTPb{uy54V}aH@ z6i(BCB))@2YjO%A{fpzt7Q&z7>v^tLs^SAYmK`h%@N`-~P$=gKSn9AqYbgp7HIVw{ z*(8-|5o-(R=Mw_0=_%k$jRjhdP+>pnsUCcv5KVE6znzSO~z)Qnv zQbNEohvCAmBOG6E)6(%u+>msQ`mggVz8{}%QJGz%%;)ej4(mBw&EYx@@8s})4!3aF z$Kfj+zR%&89F90kVqp@8XLDG_;d~A+E48 zTtA0rb6CdVd=4+;u%5%!9IoT=P7d$qa0`ch9KOP#rcIK>_W=biAihR9%U*z$&N+5x zS)sGgX)i7+E-NZ6DH0r+p$TNO^eO#Ik0F8Dvk5z0@g06UPo>l4O#GCdg;AmhuWV8f zdu17MqSHS=qA*nh(oX=1K9$qiz6Z1qINd%=V-$N_8nB3eAE&c@E?Caw^q+G%w6~=Y zOZ@~nY$(|{oPvLp>V2%NQl>t4#=;)9100DuX1yGkb! z%;aaE0sR^S`UawBu}&ad!ytX_mg+sdfBnKhP8jVjlRd`__!na0$;3}z`OWlw{2M_h zzio7BX1>j>ebzwE-wo)KP*fT>();`O82t=sD<6l2GYVL}2y76}GN9LSIUQ-^N!Wn@ zJ_CBc0e!rIpIZ#*YYpi48PJ~uJ(HiaFtul@ukRSp&j;N;=&n?3fdT(Y1Nt8g=(|84 zmy$Xdc^7p1AexGOZa^Q44Nj(VT>(1zVN<0h;s}@YbI>#0_wXp_neKZyU?Bepm*2tX zy9L71>OgDMS=fT_m)EWg`J=U~=)>jgM5izi4&$ruK4(!Rj4$Zp^XZXjRq3LZx?pH= zsM_f-WT!O(n%1UsG9eDSk^T zX40<{KgBc3W|o$hlsRVraT2ApxT3V8Y-VuxV)^ih**ePT2x#-v!rO| z3=-)qXFty3(vp(m86_Ts(Bc|Y&Z6ofzq5#((&Ue>2?sr*s_4`FTDj0N*=-WlXr6;t zllY@ebPYsvFoHH)*WzE**s>C}R~Kz*jreQZ+ND5CQ@Al04c1WwX5yev{)ccyMr-XF zcp%!kMyiJuL4RFaQxkp2Ux%^VB!;lUDBN;DCi(sI7rPdE{GLT_x6J5Tao|u(5{K7WFPz2zS_^L^IxK}oK9Q@ zu`1Y1_dL|mZ4haf9B6jqk^;JUz#ptbV`c~PL+K}T?@8JaYkwt&4jkqjFF90`H&@C!Pw~6RkMP&`SS!9Tdsq2G_uG`RE1(GTqF4N%mdZb9y zw5e9ZYf>cKzJW;+w|k^0#3agj;)O++v;H*(-#{b3(&Z$sq|wTn8l%`HOgh)HT0%k7 zIvicEGc;$~{VgdMmP%}}Mdje~DKV&0z5n03mq%}gu-0HHk>TPW?RKi6x8n?vh*2s1 zj+j*0aEFU_>k+Qa(Pui@j_SodL$u5ZV3AY8ZrwFAiFa5HNk6GkzBs+{Fay{k zH(fZpUQJ(wZ@(sP$OTT7;vS=uszsXq2XC^{o4}`}x->7Q4Z8XqZx272qG#G8wQdVP=LicAe zHjem_)*5WAr3^e4Zj6#dT257;NCn_=Y;<6&MUbYt3P3>%Y{E|=GgLDQ z!=Qw%O%vVBC-&d}O-SdVcw~oX^jcVt=h_qmbZBVmS3Ex!ghE72_!Idb78cU&r^o7aW-9WFb5a3Yc|Kvk;1lo)q|+I!z}d?|lqZj88{kNOmf}c*w+|I0qK`MSfBK)ja=PE>N5+3nC zsmxXpC-@`$>GRv|M3p1~dr}3{=)x@mt^--0U!3O&Sbmn4PyAMj2!|U0_4&nfcLDL( zYe*1&6vW#Rq5LT`sX?)Q7ZuW2Y3 ziZ~Q@3usTvFWzHOdHygJP8UQz0nbUxFU~oZ)@qsTy1Wz>`2?BH$%!V)FU~RAdH(WL z$JBCEii{l6N3QTcd#6*MB=V<^U&Kp657Shz^t)>rka}>gLt!%hXf71?i+ZJGVLPI! gu=HvzI)@skE(pDXM8kZh{Qtg2 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +constexpr int NIL = -1; +constexpr int MAX_RESULT_SLOTS = 4096; + +struct Node { + int32_t value; + int next; +}; + +struct SharedData { + int results[MAX_RESULT_SLOTS]; + Node nodes[1]; +}; + +struct Options { + size_t size = 100000; + int max_depth = 3; + size_t min_size = 4096; + unsigned seed = 1337; + bool print = false; +}; + +struct SortResult { + int head = NIL; + uint64_t processes = 1; +}; + +static void throw_errno(const std::string& what) { + throw std::runtime_error(what + ": " + std::strerror(errno)); +} + +static int merge_lists(Node* nodes, int left, int right) { + if (left == NIL) return right; + if (right == NIL) return left; + + int head = NIL; + int tail = NIL; + + auto append = [&](int idx) { + if (head == NIL) { + head = idx; + tail = idx; + } else { + nodes[tail].next = idx; + tail = idx; + } + }; + + while (left != NIL && right != NIL) { + if (nodes[left].value <= nodes[right].value) { + int next = nodes[left].next; + append(left); + left = next; + } else { + int next = nodes[right].next; + append(right); + right = next; + } + } + + if (left != NIL) nodes[tail].next = left; + if (right != NIL) nodes[tail].next = right; + return head; +} + +static void split_list(Node* nodes, int head, int& left, int& right) { + if (head == NIL || nodes[head].next == NIL) { + left = head; + right = NIL; + return; + } + + int slow = head; + int fast = nodes[head].next; + + while (fast != NIL) { + fast = nodes[fast].next; + if (fast != NIL) { + slow = nodes[slow].next; + fast = nodes[fast].next; + } + } + + left = head; + right = nodes[slow].next; + nodes[slow].next = NIL; +} + +static int local_sort(Node* nodes, int head) { + if (head == NIL || nodes[head].next == NIL) return head; + + int left = NIL; + int right = NIL; + split_list(nodes, head, left, right); + left = local_sort(nodes, left); + right = local_sort(nodes, right); + return merge_lists(nodes, left, right); +} + +static size_t list_length(const Node* nodes, int head) { + size_t n = 0; + while (head != NIL) { + ++n; + head = nodes[head].next; + } + return n; +} + +static SortResult parallel_sort(SharedData* data, + int head, + int depth, + const Options& opt, + int slot) { + const size_t n = list_length(data->nodes, head); + + if (head == NIL || data->nodes[head].next == NIL || + depth >= opt.max_depth || n <= opt.min_size) { + return {local_sort(data->nodes, head), 1}; + } + + int left = NIL; + int right = NIL; + split_list(data->nodes, head, left, right); + + const int left_slot = slot * 2 + 1; + const int right_slot = slot * 2 + 2; + + if (right_slot >= MAX_RESULT_SLOTS) { + int sorted_left = local_sort(data->nodes, left); + int sorted_right = local_sort(data->nodes, right); + return {merge_lists(data->nodes, sorted_left, sorted_right), 1}; + } + + pid_t left_pid = fork(); + if (left_pid < 0) throw_errno("fork left"); + + if (left_pid == 0) { + try { + SortResult r = parallel_sort(data, left, depth + 1, opt, left_slot); + data->results[left_slot] = r.head; + _exit(0); + } catch (...) { + _exit(2); + } + } + + pid_t right_pid = fork(); + if (right_pid < 0) throw_errno("fork right"); + + if (right_pid == 0) { + try { + SortResult r = parallel_sort(data, right, depth + 1, opt, right_slot); + data->results[right_slot] = r.head; + _exit(0); + } catch (...) { + _exit(2); + } + } + + int left_status = 0; + int right_status = 0; + + while (waitpid(left_pid, &left_status, 0) < 0 && errno == EINTR) {} + while (waitpid(right_pid, &right_status, 0) < 0 && errno == EINTR) {} + + if (!WIFEXITED(left_status) || WEXITSTATUS(left_status) != 0) { + throw std::runtime_error("left child failed"); + } + if (!WIFEXITED(right_status) || WEXITSTATUS(right_status) != 0) { + throw std::runtime_error("right child failed"); + } + + return {merge_lists(data->nodes, data->results[left_slot], data->results[right_slot]), + static_cast((1ULL << (depth + 2)) - 1ULL)}; +} + +static Options parse_args(int argc, char** argv) { + Options opt; + + for (int i = 1; i < argc; ++i) { + std::string s = argv[i]; + + auto value = [&](const std::string& name) -> std::string { + if (i + 1 >= argc) throw std::runtime_error("missing value for " + name); + return argv[++i]; + }; + + if (s == "--size" || s == "-n") { + opt.size = std::stoull(value(s)); + } else if (s == "--depth" || s == "-d") { + opt.max_depth = std::stoi(value(s)); + } else if (s == "--min-size" || s == "-m") { + opt.min_size = std::stoull(value(s)); + } else if (s == "--seed") { + opt.seed = static_cast(std::stoul(value(s))); + } else if (s == "--print") { + opt.print = true; + } else if (s == "--help" || s == "-h") { + std::cout << "Usage: ./shm_sort [--size N] [--depth D] [--min-size M] " + << "[--seed S] [--print]\n"; + std::exit(0); + } else { + throw std::runtime_error("unknown argument: " + s); + } + } + + if (opt.max_depth < 0) throw std::runtime_error("depth must be non-negative"); + if (opt.size == 0) throw std::runtime_error("size must be positive"); + return opt; +} + +static bool is_sorted_list(const Node* nodes, int head, size_t expected) { + size_t seen = 0; + int32_t prev = 0; + bool first = true; + + while (head != NIL) { + if (!first && prev > nodes[head].value) return false; + first = false; + prev = nodes[head].value; + head = nodes[head].next; + ++seen; + } + + return seen == expected; +} + +int main(int argc, char** argv) { + int shmid = -1; + SharedData* data = reinterpret_cast(-1); + + try { + Options opt = parse_args(argc, argv); + const size_t shm_size = sizeof(SharedData) + sizeof(Node) * (opt.size - 1); + + shmid = shmget(IPC_PRIVATE, shm_size, IPC_CREAT | 0600); + if (shmid < 0) throw_errno("shmget"); + + data = static_cast(shmat(shmid, nullptr, 0)); + if (data == reinterpret_cast(-1)) throw_errno("shmat"); + + std::fill(data->results, data->results + MAX_RESULT_SLOTS, NIL); + + std::mt19937 rng(opt.seed); + std::uniform_int_distribution dist(-100000000, 100000000); + + for (size_t i = 0; i < opt.size; ++i) { + data->nodes[i].value = dist(rng); + data->nodes[i].next = (i + 1 == opt.size) ? NIL : static_cast(i + 1); + } + + const auto t1 = std::chrono::steady_clock::now(); + SortResult result = parallel_sort(data, 0, 0, opt, 0); + const auto t2 = std::chrono::steady_clock::now(); + + const double elapsed = std::chrono::duration(t2 - t1).count(); + const bool ok = is_sorted_list(data->nodes, result.head, opt.size); + + if (opt.print) { + for (int cur = result.head; cur != NIL; cur = data->nodes[cur].next) { + std::cout << data->nodes[cur].value << ' '; + } + std::cout << '\n'; + } + + std::cerr << "STAT: program=shm size=" << opt.size + << " depth=" << opt.max_depth + << " min_size=" << opt.min_size + << " valid=" << (ok ? 1 : 0) + << " time=" << elapsed << " sec\n"; + + shmdt(data); + shmctl(shmid, IPC_RMID, nullptr); + return ok ? 0 : 3; + } catch (const std::exception& e) { + if (data != reinterpret_cast(-1)) shmdt(data); + if (shmid >= 0) shmctl(shmid, IPC_RMID, nullptr); + std::cerr << "ERROR: " << e.what() << "\n"; + return 1; + } +}