updtae
This commit is contained in:
parent
61aa7782c3
commit
1367ce183c
228
html/input.php
228
html/input.php
|
|
@ -3,74 +3,113 @@
|
||||||
|
|
||||||
$coreFile = "/var/www/core.json";
|
$coreFile = "/var/www/core.json";
|
||||||
|
|
||||||
if (!file_exists($coreFile)) {
|
/* ---------------------------------------------------------
|
||||||
file_put_contents($coreFile, json_encode([]));
|
STATE HELPERS
|
||||||
|
--------------------------------------------------------- */
|
||||||
|
|
||||||
|
function loadCoreState(): array
|
||||||
|
{
|
||||||
|
global $coreFile;
|
||||||
|
|
||||||
|
if (!file_exists($coreFile)) {
|
||||||
|
return ["cursor" => 0, "allocations" => []];
|
||||||
|
}
|
||||||
|
|
||||||
|
$state = json_decode(file_get_contents($coreFile), true);
|
||||||
|
return $state ?: ["cursor" => 0, "allocations" => []];
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ---------- STEP 1: READ & COUNT NUMA TOPOLOGY ---------- */
|
function saveCoreState(array $state): void
|
||||||
|
{
|
||||||
|
global $coreFile;
|
||||||
|
file_put_contents($coreFile, json_encode($state, JSON_PRETTY_PRINT));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ---------------------------------------------------------
|
||||||
|
NUMA + SMT TOPOLOGY (SOURCE OF TRUTH)
|
||||||
|
--------------------------------------------------------- */
|
||||||
|
|
||||||
function getNumaTopology(): array
|
function getNumaTopology(): array
|
||||||
{
|
{
|
||||||
$out = shell_exec("numactl --hardware");
|
|
||||||
$nodes = [];
|
$nodes = [];
|
||||||
|
|
||||||
foreach (explode("\n", $out) as $line) {
|
/* discover nodes */
|
||||||
if (preg_match('/node (\d+) cpus:\s+(.*)/', $line, $m)) {
|
foreach (glob('/sys/devices/system/node/node*') as $nodePath) {
|
||||||
$node = (int)$m[1];
|
$node = (int)str_replace('node', '', basename($nodePath));
|
||||||
$cpus = array_map('intval', preg_split('/\s+/', trim($m[2])));
|
$nodes[$node] = [];
|
||||||
sort($cpus);
|
}
|
||||||
|
|
||||||
$nodes[$node] = [
|
/* read cpu → node + core_id */
|
||||||
"all" => $cpus,
|
foreach (glob('/sys/devices/system/cpu/cpu[0-9]*') as $cpuPath) {
|
||||||
"even" => array_values(array_filter($cpus, fn($c) => $c % 2 === 0)),
|
$cpu = (int)str_replace('cpu', '', basename($cpuPath));
|
||||||
"odd" => array_values(array_filter($cpus, fn($c) => $c % 2 === 1)),
|
$topo = "$cpuPath/topology";
|
||||||
];
|
|
||||||
|
if (!is_dir($topo)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$coreId = (int)trim(file_get_contents("$topo/core_id"));
|
||||||
|
|
||||||
|
$node = null;
|
||||||
|
foreach (glob("$cpuPath/node*") as $n) {
|
||||||
|
$node = (int)str_replace('node', '', basename($n));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($node === null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$nodes[$node][$coreId][] = $cpu;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* normalize ordering */
|
||||||
|
ksort($nodes);
|
||||||
|
foreach ($nodes as &$cores) {
|
||||||
|
ksort($cores);
|
||||||
|
foreach ($cores as &$threads) {
|
||||||
|
sort($threads); // primary thread first
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ksort($nodes);
|
|
||||||
return $nodes;
|
return $nodes;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ---------- STEP 2: BUILD GLOBAL ROUND-ROBIN PLAN ---------- */
|
/* ---------------------------------------------------------
|
||||||
|
BUILD GLOBAL ROUND-ROBIN PLAN
|
||||||
|
--------------------------------------------------------- */
|
||||||
|
|
||||||
function buildAllocationPlan(array $nodes): array
|
function buildAllocationPlan(array $nodes): array
|
||||||
{
|
{
|
||||||
$plan = [];
|
$plan = [];
|
||||||
$nodeIds = array_keys($nodes);
|
|
||||||
$nodeCount = count($nodeIds);
|
|
||||||
|
|
||||||
if ($nodeCount === 0) {
|
if (empty($nodes)) {
|
||||||
return $plan;
|
return $plan;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* EVEN cores first (physical cores) */
|
$maxCores = max(array_map('count', $nodes));
|
||||||
$maxEven = 0;
|
|
||||||
foreach ($nodes as $n) {
|
|
||||||
$maxEven = max($maxEven, count($n["even"]));
|
|
||||||
}
|
|
||||||
|
|
||||||
for ($coreIndex = 0; $coreIndex < $maxEven; $coreIndex++) {
|
/* PASS 1 — physical cores only */
|
||||||
foreach ($nodeIds as $node) {
|
for ($i = 0; $i < $maxCores; $i++) {
|
||||||
if (isset($nodes[$node]["even"][$coreIndex])) {
|
foreach ($nodes as $node => $cores) {
|
||||||
|
$coreIds = array_keys($cores);
|
||||||
|
if (isset($coreIds[$i])) {
|
||||||
$plan[] = [
|
$plan[] = [
|
||||||
"node" => $node,
|
"node" => $node,
|
||||||
"cpu" => $nodes[$node]["even"][$coreIndex]
|
"cpu" => $cores[$coreIds[$i]][0]
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ODD cores next (hyper-threads) */
|
/* PASS 2 — SMT siblings */
|
||||||
$maxOdd = 0;
|
for ($i = 0; $i < $maxCores; $i++) {
|
||||||
foreach ($nodes as $n) {
|
foreach ($nodes as $node => $cores) {
|
||||||
$maxOdd = max($maxOdd, count($n["odd"]));
|
$coreIds = array_keys($cores);
|
||||||
}
|
if (isset($coreIds[$i]) && count($cores[$coreIds[$i]]) > 1) {
|
||||||
|
|
||||||
for ($coreIndex = 0; $coreIndex < $maxOdd; $coreIndex++) {
|
|
||||||
foreach ($nodeIds as $node) {
|
|
||||||
if (isset($nodes[$node]["odd"][$coreIndex])) {
|
|
||||||
$plan[] = [
|
$plan[] = [
|
||||||
"node" => $node,
|
"node" => $node,
|
||||||
"cpu" => $nodes[$node]["odd"][$coreIndex]
|
"cpu" => $cores[$coreIds[$i]][1]
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -79,12 +118,18 @@ function buildAllocationPlan(array $nodes): array
|
||||||
return $plan;
|
return $plan;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ---------- STEP 3: ALLOCATE USING PRECOMPUTED PLAN ---------- */
|
/* ---------------------------------------------------------
|
||||||
|
ALLOCATION API
|
||||||
|
--------------------------------------------------------- */
|
||||||
|
|
||||||
function allocateCore(int $serviceId): array
|
function allocateCore(int $serviceId): array
|
||||||
{
|
{
|
||||||
global $coreFile;
|
$state = loadCoreState();
|
||||||
|
|
||||||
|
if (isset($state["allocations"][$serviceId])) {
|
||||||
|
return $state["allocations"][$serviceId];
|
||||||
|
}
|
||||||
|
|
||||||
$map = json_decode(file_get_contents($coreFile), true) ?: [];
|
|
||||||
$nodes = getNumaTopology();
|
$nodes = getNumaTopology();
|
||||||
$plan = buildAllocationPlan($nodes);
|
$plan = buildAllocationPlan($nodes);
|
||||||
|
|
||||||
|
|
@ -92,32 +137,29 @@ function allocateCore(int $serviceId): array
|
||||||
return ["node" => 0, "cpu" => 0];
|
return ["node" => 0, "cpu" => 0];
|
||||||
}
|
}
|
||||||
|
|
||||||
$index = count($map);
|
$slot = $plan[$state["cursor"] % count($plan)];
|
||||||
$slot = $plan[$index % count($plan)];
|
$state["cursor"]++;
|
||||||
|
|
||||||
$map[$serviceId] = $slot;
|
$state["allocations"][$serviceId] = $slot;
|
||||||
file_put_contents($coreFile, json_encode($map, JSON_PRETTY_PRINT));
|
saveCoreState($state);
|
||||||
|
|
||||||
return $slot;
|
return $slot;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ---------- HELPERS ---------- */
|
|
||||||
function freeCore(int $serviceId): void
|
function freeCore(int $serviceId): void
|
||||||
{
|
{
|
||||||
global $coreFile;
|
$state = loadCoreState();
|
||||||
$map = json_decode(file_get_contents($coreFile), true) ?: [];
|
|
||||||
|
|
||||||
if (isset($map[$serviceId])) {
|
if (isset($state["allocations"][$serviceId])) {
|
||||||
unset($map[$serviceId]);
|
unset($state["allocations"][$serviceId]);
|
||||||
file_put_contents($coreFile, json_encode($map, JSON_PRETTY_PRINT));
|
saveCoreState($state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function getServiceCore(int $serviceId): ?array
|
function getServiceCore(int $serviceId): ?array
|
||||||
{
|
{
|
||||||
global $coreFile;
|
$state = loadCoreState();
|
||||||
$map = json_decode(file_get_contents($coreFile), true) ?: [];
|
return $state["allocations"][$serviceId] ?? null;
|
||||||
return $map[$serviceId] ?? null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$jsonFile = __DIR__ . "/input.json";
|
$jsonFile = __DIR__ . "/input.json";
|
||||||
|
|
@ -161,42 +203,26 @@ if ($_SERVER["REQUEST_METHOD"] === "POST" && $_POST["action"] === "add") {
|
||||||
$core = (int)$alloc["cpu"];
|
$core = (int)$alloc["cpu"];
|
||||||
$node = (int)$alloc["node"];
|
$node = (int)$alloc["node"];
|
||||||
|
|
||||||
$ffmpeg = 'numactl --cpunodebind=' . $node .
|
$ffmpeg = 'numactl --cpunodebind=' . $node
|
||||||
' --membind=' . $node .
|
. ' --membind=' . $node
|
||||||
' taskset -c ' . $core . ' ffmpeg -hide_banner -loglevel info \
|
. ' taskset -c ' . $core
|
||||||
-thread_queue_size 65536 \
|
. ' ffmpeg -hide_banner -loglevel info -thread_queue_size 65536 -fflags +genpts+discardcorrupt+nobuffer -readrate 1.0'
|
||||||
-fflags +genpts+discardcorrupt+nobuffer \
|
. ' -i "udp://@' . $new["input_udp"] . '?fifo_size=100000000&buffer_size=100000000&overrun_nonfatal=1"'
|
||||||
-readrate 1.0 \
|
. ' -vf "yadif=mode=0:deint=0,scale=' . $new["resolution"] . ',format=yuv420p" '
|
||||||
-i "udp://@' . $new["input_udp"] . '?fifo_size=100000000&buffer_size=100000000&overrun_nonfatal=1" \
|
. ' -c:v ' . $new["video_format"] . ' -flags -ildct-ilme -threads 1 -g 10 -bf 0 '
|
||||||
-vf "setpts=PTS-STARTPTS,yadif=mode=0:parity=0:deint=0,scale=' . $new["resolution"] . ',format=yuv420p" \
|
. ' -b:v ' . $new["video_bitrate"] . 'k -minrate ' . max(0, $new["video_bitrate"] - 500) . 'k -maxrate ' . ($new["video_bitrate"] + 500) . 'k -bufsize 1835k '
|
||||||
-c:v ' . $new["video_format"] . ' \
|
. ' -c:a ' . $new["audio_format"] . ' -b:a ' . $new["audio_bitrate"] . 'k -ar 48000 -ac 2 -af "volume=' . $new["volume"] . 'dB,aresample=async=1:first_pts=0" '
|
||||||
-threads 1 \
|
. ' -metadata service_provider="ShreeBhattJI" ';
|
||||||
-r 25 \
|
|
||||||
-fps_mode cfr \
|
|
||||||
-g 12 \
|
|
||||||
-bf 0 \
|
|
||||||
-b:v ' . $new["video_bitrate"] . 'k \
|
|
||||||
-minrate ' . $new["video_bitrate"] . 'k \
|
|
||||||
-maxrate ' . $new["video_bitrate"] . 'k \
|
|
||||||
-bufsize ' . $new["video_bitrate"] . 'k \
|
|
||||||
-c:a ' . $new["audio_format"] . ' \
|
|
||||||
-b:a ' . $new["audio_bitrate"] . 'k \
|
|
||||||
-ar 48000 -ac 2 \
|
|
||||||
-af "volume=' . $new["volume"] . 'dB,aresample=async=1000" \
|
|
||||||
-metadata service_provider="ShreeBhattJI" ';
|
|
||||||
if ($new["service_name"] !== "") {
|
if ($new["service_name"] !== "") {
|
||||||
$ffmpeg .= '-metadata service_name="' . $new["service_name"] . '" ';
|
$ffmpeg .= '-metadata service_name="' . $new["service_name"] . '" ';
|
||||||
}
|
}
|
||||||
$ffmpeg .= '-pcr_period 20 \
|
$ffmpeg .= ' -pcr_period 20 -f mpegts "udp://' . $new["output_udp"] . '?pkt_size=1316&bitrate=4500000&flush_packets=1"';
|
||||||
-f mpegts "udp://' . $new["output_udp"] . '?pkt_size=1316&bitrate=4500000&flush_packets=1"';
|
|
||||||
|
|
||||||
|
|
||||||
if ($new["service_name"] !== "")
|
if ($new["service_name"] !== "")
|
||||||
$ffmpeg .= '-metadata service_name="' . $new["service_name"] . '"';
|
$ffmpeg .= '-metadata service_name="' . $new["service_name"] . '"';
|
||||||
$ffmpeg .= ' -f mpegts "udp://@' . $new["output_udp"] . '?pkt_size=1316&bitrate=4500000"';
|
$ffmpeg .= ' -f mpegts "udp://@' . $new["output_udp"] . '?pkt_size=1316&bitrate=4500000"';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
file_put_contents("/var/www/encoder/{$new["id"]}.sh", $ffmpeg);
|
file_put_contents("/var/www/encoder/{$new["id"]}.sh", $ffmpeg);
|
||||||
|
|
||||||
if ($new["service"] === "enable") {
|
if ($new["service"] === "enable") {
|
||||||
|
|
@ -261,36 +287,26 @@ if ($_SERVER["REQUEST_METHOD"] === "POST" && $_POST["action"] === "edit") {
|
||||||
$node = (int)$alloc["node"];
|
$node = (int)$alloc["node"];
|
||||||
|
|
||||||
|
|
||||||
$ffmpeg = 'numactl --cpunodebind=' . $node .
|
$ffmpeg = 'numactl --cpunodebind=' . $node
|
||||||
' --membind=' . $node .
|
. ' --membind=' . $node
|
||||||
' taskset -c ' . $core . ' ffmpeg -hide_banner -loglevel info \
|
. ' taskset -c ' . $core
|
||||||
-thread_queue_size 65536 \
|
. ' ffmpeg -hide_banner -loglevel info -thread_queue_size 65536 -fflags +genpts+discardcorrupt+nobuffer -readrate 1.0'
|
||||||
-fflags +genpts+discardcorrupt+nobuffer \
|
. ' -i "udp://@' . $new["input_udp"] . '?fifo_size=100000000&buffer_size=100000000&overrun_nonfatal=1"'
|
||||||
-readrate 1.0 \
|
. ' -vf "yadif=mode=0:deint=0,scale=' . $new["resolution"] . ',format=yuv420p" '
|
||||||
-i "udp://@' . $new["input_udp"] . '?fifo_size=100000000&buffer_size=100000000&overrun_nonfatal=1" \
|
. ' -c:v ' . $new["video_format"] . ' -flags -ildct-ilme -threads 1 -g 10 -bf 0 '
|
||||||
-vf "setpts=PTS-STARTPTS,yadif=mode=0:parity=0:deint=0,scale=' . $new["resolution"] . ',format=yuv420p" \
|
. ' -b:v ' . $new["video_bitrate"] . 'k -minrate ' . max(0, $new["video_bitrate"] - 500) . 'k -maxrate ' . ($new["video_bitrate"] + 500) . 'k -bufsize 1835k '
|
||||||
-c:v ' . $new["video_format"] . ' \
|
. ' -c:a ' . $new["audio_format"] . ' -b:a ' . $new["audio_bitrate"] . 'k -ar 48000 -ac 2 -af "volume=' . $new["volume"] . 'dB,aresample=async=1:first_pts=0" '
|
||||||
-threads 1 \
|
. ' -metadata service_provider="ShreeBhattJI" ';
|
||||||
-r 25 \
|
|
||||||
-fps_mode cfr \
|
|
||||||
-g 12 \
|
|
||||||
-bf 0 \
|
|
||||||
-b:v ' . $new["video_bitrate"] . 'k \
|
|
||||||
-minrate ' . $new["video_bitrate"] . 'k \
|
|
||||||
-maxrate ' . $new["video_bitrate"] . 'k \
|
|
||||||
-bufsize ' . $new["video_bitrate"] . 'k \
|
|
||||||
-c:a ' . $new["audio_format"] . ' \
|
|
||||||
-b:a ' . $new["audio_bitrate"] . 'k \
|
|
||||||
-ar 48000 -ac 2 \
|
|
||||||
-af "volume=' . $new["volume"] . 'dB,aresample=async=1000" \
|
|
||||||
-metadata service_provider="ShreeBhattJI" ';
|
|
||||||
if ($new["service_name"] !== "") {
|
if ($new["service_name"] !== "") {
|
||||||
$ffmpeg .= '-metadata service_name="' . $new["service_name"] . '" ';
|
$ffmpeg .= '-metadata service_name="' . $new["service_name"] . '" ';
|
||||||
}
|
}
|
||||||
$ffmpeg .= '-pcr_period 20 \
|
$ffmpeg .= ' -pcr_period 20 -f mpegts "udp://' . $new["output_udp"] . '?pkt_size=1316&bitrate=4500000&flush_packets=1"';
|
||||||
-f mpegts "udp://' . $new["output_udp"] . '?pkt_size=1316&bitrate=4500000&flush_packets=1"';
|
|
||||||
|
|
||||||
|
|
||||||
|
if ($new["service_name"] !== "")
|
||||||
|
$ffmpeg .= '-metadata service_name="' . $new["service_name"] . '"';
|
||||||
|
$ffmpeg .= ' -f mpegts "udp://@' . $new["output_udp"] . '?pkt_size=1316&bitrate=4500000"';
|
||||||
|
|
||||||
|
|
||||||
file_put_contents("/var/www/encoder/$id.sh", $ffmpeg);
|
file_put_contents("/var/www/encoder/$id.sh", $ffmpeg);
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue