[Phi] adding basic host emulation for development without access to a
Xeon Phi
This commit is contained in:
@@ -235,6 +235,28 @@ To bring forth the driver:
|
|||||||
zig build phi --release=[fast|safe|small]
|
zig build phi --release=[fast|safe|small]
|
||||||
```
|
```
|
||||||
|
|
||||||
|
To build Phi without a Xeon Phi card, enable host emulation:
|
||||||
|
|
||||||
|
```
|
||||||
|
zig build phi -Dphi-host-emulation=true --release=[fast|safe|small]
|
||||||
|
```
|
||||||
|
|
||||||
|
In this mode the daemon is compiled natively through Zig's `std.Build` C compilation support and installed as `zig-out/bin/phi_device-host`. The driver exposes one synthetic Phi physical device and communicates with the daemon over an IPv4 TCP socket bound only to `127.0.0.1`. The client socket is implemented directly with Zig's `std.Io.net` API; it does not reuse daemon C transport functions or load `libmicmgmt` or `libscif`.
|
||||||
|
|
||||||
|
The driver first connects to an already-running daemon. If none is listening, it launches its embedded daemon locally and retries the connection. The temporary embedded executable removes its own filesystem entry after launch. The daemon may also be started manually:
|
||||||
|
|
||||||
|
```
|
||||||
|
./zig-out/bin/phi_device-host
|
||||||
|
```
|
||||||
|
|
||||||
|
The loopback port defaults to `43616` and may be selected at build time for both the driver and daemon:
|
||||||
|
|
||||||
|
```
|
||||||
|
zig build phi -Dphi-host-emulation=true -Dphi-emulation-port=43617
|
||||||
|
```
|
||||||
|
|
||||||
|
Builds without `-Dphi-host-emulation=true` retain the real Xeon Phi path: the daemon is cross-compiled with the configured `k1om-mpss-linux-gcc`, deployed over SSH/SCP, and communicates through SCIF.
|
||||||
|
|
||||||
And for those who seek another manner of building:
|
And for those who seek another manner of building:
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ const ImplementationDesc = struct {
|
|||||||
vulkan_version: std.SemanticVersion,
|
vulkan_version: std.SemanticVersion,
|
||||||
custom: ?*const fn (
|
custom: ?*const fn (
|
||||||
*std.Build,
|
*std.Build,
|
||||||
|
*Step.Options,
|
||||||
*Step.Compile,
|
*Step.Compile,
|
||||||
*std.Build.Module,
|
*std.Build.Module,
|
||||||
*std.Build.Module,
|
*std.Build.Module,
|
||||||
@@ -20,37 +21,32 @@ const ImplementationDesc = struct {
|
|||||||
std.builtin.OptimizeMode,
|
std.builtin.OptimizeMode,
|
||||||
bool,
|
bool,
|
||||||
) anyerror!void = null,
|
) anyerror!void = null,
|
||||||
options: ?*const fn (*std.Build, *Step.Options) anyerror!void = null,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const implementations = [_]ImplementationDesc{
|
const implementations = [_]ImplementationDesc{
|
||||||
.{
|
|
||||||
.name = "ape",
|
|
||||||
.icd_name = "ape",
|
|
||||||
.root_source_file = "src/ape/lib.zig",
|
|
||||||
.vulkan_version = .{ .major = 1, .minor = 0, .patch = 0 },
|
|
||||||
.custom = customApe,
|
|
||||||
},
|
|
||||||
.{
|
.{
|
||||||
.name = "soft",
|
.name = "soft",
|
||||||
.root_source_file = "src/software/lib.zig",
|
.root_source_file = "src/software/lib.zig",
|
||||||
.vulkan_version = .{ .major = 1, .minor = 0, .patch = 0 },
|
.vulkan_version = .{ .major = 1, .minor = 0, .patch = 0 },
|
||||||
.custom = customSoft,
|
.custom = customSoft,
|
||||||
.options = optionsSoft,
|
|
||||||
},
|
},
|
||||||
.{
|
.{
|
||||||
.name = "flint",
|
.name = "flint",
|
||||||
.root_source_file = "src/intel/lib.zig",
|
.root_source_file = "src/intel/lib.zig",
|
||||||
.vulkan_version = .{ .major = 1, .minor = 0, .patch = 0 },
|
.vulkan_version = .{ .major = 1, .minor = 0, .patch = 0 },
|
||||||
.custom = customFlint,
|
.custom = customFlint,
|
||||||
.options = optionsFlint,
|
|
||||||
},
|
},
|
||||||
.{
|
.{
|
||||||
.name = "phi",
|
.name = "phi",
|
||||||
.root_source_file = "src/phi/lib.zig",
|
.root_source_file = "src/phi/lib.zig",
|
||||||
.vulkan_version = .{ .major = 1, .minor = 0, .patch = 0 },
|
.vulkan_version = .{ .major = 1, .minor = 0, .patch = 0 },
|
||||||
.custom = customPhi,
|
.custom = customPhi,
|
||||||
.options = optionsPhi,
|
},
|
||||||
|
.{
|
||||||
|
.name = "ape",
|
||||||
|
.icd_name = "ape",
|
||||||
|
.root_source_file = "src/ape/lib.zig",
|
||||||
|
.vulkan_version = .{ .major = 1, .minor = 0, .patch = 0 },
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -149,7 +145,8 @@ pub fn build(b: *std.Build) !void {
|
|||||||
|
|
||||||
const use_llvm = b.option(bool, "use-llvm", "LLVM build") orelse (b.release_mode != .off);
|
const use_llvm = b.option(bool, "use-llvm", "LLVM build") orelse (b.release_mode != .off);
|
||||||
|
|
||||||
for (implementations) |impl| {
|
var implementation_modules: [implementations.len]*std.Build.Module = undefined;
|
||||||
|
for (implementations, 0..) |impl, impl_index| {
|
||||||
const lib_mod = b.createModule(.{
|
const lib_mod = b.createModule(.{
|
||||||
.root_source_file = b.path(impl.root_source_file),
|
.root_source_file = b.path(impl.root_source_file),
|
||||||
.target = target,
|
.target = target,
|
||||||
@@ -161,6 +158,7 @@ pub fn build(b: *std.Build) !void {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
implementation_modules[impl_index] = lib_mod;
|
||||||
lib_mod.addSystemIncludePath(vulkan_headers.path("include"));
|
lib_mod.addSystemIncludePath(vulkan_headers.path("include"));
|
||||||
|
|
||||||
const lib = b.addLibrary(.{
|
const lib = b.addLibrary(.{
|
||||||
@@ -172,12 +170,11 @@ pub fn build(b: *std.Build) !void {
|
|||||||
|
|
||||||
options.addOption(std.SemanticVersion, b.fmt("{s}_vulkan_version", .{impl.name}), impl.vulkan_version);
|
options.addOption(std.SemanticVersion, b.fmt("{s}_vulkan_version", .{impl.name}), impl.vulkan_version);
|
||||||
|
|
||||||
if (impl.custom) |func| {
|
if (std.mem.eql(u8, impl.name, "ape")) {
|
||||||
func(b, lib, lib_mod, base_mod, vulkan, base_c_mod, target, optimize, use_llvm) catch continue;
|
for (implementations[0..impl_index], implementation_modules[0..impl_index]) |child_impl, child_mod|
|
||||||
}
|
lib_mod.addImport(child_impl.name, child_mod);
|
||||||
|
} else if (impl.custom) |func| {
|
||||||
if (impl.options) |func| {
|
func(b, options, lib, lib_mod, base_mod, vulkan, base_c_mod, target, optimize, use_llvm) catch continue;
|
||||||
func(b, options) catch continue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const icd_file = b.addWriteFile(
|
const icd_file = b.addWriteFile(
|
||||||
@@ -426,45 +423,11 @@ fn addMultithreadedCTS(b: *std.Build, target: std.Build.ResolvedTarget, impl: *c
|
|||||||
return &run.step;
|
return &run.step;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ape specialized functions
|
|
||||||
|
|
||||||
fn customApe(
|
|
||||||
b: *std.Build,
|
|
||||||
lib: *Step.Compile,
|
|
||||||
lib_mod: *std.Build.Module,
|
|
||||||
base_mod: *std.Build.Module,
|
|
||||||
vulkan: *std.Build.Module,
|
|
||||||
base_c_mod: *std.Build.Module,
|
|
||||||
target: std.Build.ResolvedTarget,
|
|
||||||
optimize: std.builtin.OptimizeMode,
|
|
||||||
use_llvm: bool,
|
|
||||||
) !void {
|
|
||||||
for (implementations) |impl| {
|
|
||||||
if (std.mem.eql(u8, impl.name, "ape"))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
const mod = b.createModule(.{
|
|
||||||
.root_source_file = b.path(impl.root_source_file),
|
|
||||||
.target = target,
|
|
||||||
.optimize = optimize,
|
|
||||||
.imports = &.{
|
|
||||||
.{ .name = "base", .module = base_mod },
|
|
||||||
.{ .name = "vulkan", .module = vulkan },
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
if (impl.custom) |func| {
|
|
||||||
func(b, lib, mod, base_mod, vulkan, base_c_mod, target, optimize, use_llvm) catch continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
lib_mod.addImport(impl.name, mod);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Soft specialized functions
|
// Soft specialized functions
|
||||||
|
|
||||||
fn customSoft(
|
fn customSoft(
|
||||||
b: *std.Build,
|
b: *std.Build,
|
||||||
|
options: *Step.Options,
|
||||||
_: *Step.Compile,
|
_: *Step.Compile,
|
||||||
lib_mod: *std.Build.Module,
|
lib_mod: *std.Build.Module,
|
||||||
_: *std.Build.Module,
|
_: *std.Build.Module,
|
||||||
@@ -482,9 +445,7 @@ fn customSoft(
|
|||||||
|
|
||||||
lib_mod.addImport("soft_c", base_c_mod);
|
lib_mod.addImport("soft_c", base_c_mod);
|
||||||
lib_mod.addImport("spv", spv.module("spv"));
|
lib_mod.addImport("spv", spv.module("spv"));
|
||||||
}
|
|
||||||
|
|
||||||
fn optionsSoft(b: *std.Build, options: *Step.Options) !void {
|
|
||||||
const single_threaded_option = b.option(bool, "soft-single-threaded", "Single threaded runtime mode") orelse false;
|
const single_threaded_option = b.option(bool, "soft-single-threaded", "Single threaded runtime mode") orelse false;
|
||||||
const shaders_simd_option = b.option(bool, "soft-shader-simd", "Shaders SIMD acceleration") orelse true;
|
const shaders_simd_option = b.option(bool, "soft-shader-simd", "Shaders SIMD acceleration") orelse true;
|
||||||
const compute_dump_early_results_table_option = b.option(u32, "soft-compute-dump-early-results-table", "Dump compute shaders results table before invocation");
|
const compute_dump_early_results_table_option = b.option(u32, "soft-compute-dump-early-results-table", "Dump compute shaders results table before invocation");
|
||||||
@@ -502,6 +463,7 @@ fn optionsSoft(b: *std.Build, options: *Step.Options) !void {
|
|||||||
|
|
||||||
fn customFlint(
|
fn customFlint(
|
||||||
b: *std.Build,
|
b: *std.Build,
|
||||||
|
_: *Step.Options,
|
||||||
_: *Step.Compile,
|
_: *Step.Compile,
|
||||||
lib_mod: *std.Build.Module,
|
lib_mod: *std.Build.Module,
|
||||||
_: *std.Build.Module,
|
_: *std.Build.Module,
|
||||||
@@ -519,15 +481,11 @@ fn customFlint(
|
|||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn optionsFlint(b: *std.Build, options: *Step.Options) !void {
|
|
||||||
_ = b;
|
|
||||||
_ = options;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Phi specialized functions
|
// Phi specialized functions
|
||||||
|
|
||||||
fn customPhi(
|
fn customPhi(
|
||||||
b: *std.Build,
|
b: *std.Build,
|
||||||
|
options: *Step.Options,
|
||||||
lib: *Step.Compile,
|
lib: *Step.Compile,
|
||||||
lib_mod: *std.Build.Module,
|
lib_mod: *std.Build.Module,
|
||||||
_: *std.Build.Module,
|
_: *std.Build.Module,
|
||||||
@@ -537,8 +495,44 @@ fn customPhi(
|
|||||||
optimize: std.builtin.OptimizeMode,
|
optimize: std.builtin.OptimizeMode,
|
||||||
use_llvm: bool,
|
use_llvm: bool,
|
||||||
) !void {
|
) !void {
|
||||||
|
const daemon_remote_path = b.option(
|
||||||
|
[]const u8,
|
||||||
|
"phi-daemon-remote-path",
|
||||||
|
"Path where the Xeon Phi daemon is copied on the card",
|
||||||
|
) orelse "/tmp/phi_device.mic";
|
||||||
|
|
||||||
|
const daemon_host_prefix = b.option(
|
||||||
|
[]const u8,
|
||||||
|
"phi-daemon-host-prefix",
|
||||||
|
"Host prefix used to reach cards over ssh/scp; card N uses <prefix>N",
|
||||||
|
) orelse "mic";
|
||||||
|
|
||||||
|
options.addOption([]const u8, "phi_daemon_remote_path", daemon_remote_path);
|
||||||
|
options.addOption([]const u8, "phi_daemon_host_prefix", daemon_host_prefix);
|
||||||
|
|
||||||
|
const host_emulation = b.option(
|
||||||
|
bool,
|
||||||
|
"phi-host-emulation",
|
||||||
|
"Run the Phi device daemon on the host over a loopback TCP socket",
|
||||||
|
) orelse false;
|
||||||
|
const emulation_port = b.option(
|
||||||
|
u16,
|
||||||
|
"phi-emulation-port",
|
||||||
|
"Loopback TCP port used by Phi host emulation",
|
||||||
|
) orelse 43616;
|
||||||
|
|
||||||
|
options.addOption(bool, "phi_host_emulation", host_emulation);
|
||||||
|
options.addOption(u16, "phi_emulation_port", emulation_port);
|
||||||
|
|
||||||
lib_mod.addImport("phi_c", base_c_mod);
|
lib_mod.addImport("phi_c", base_c_mod);
|
||||||
|
|
||||||
|
if (host_emulation) {
|
||||||
|
lib_mod.addImport("miclib", b.createModule(.{
|
||||||
|
.root_source_file = b.path("src/phi/mic_stub.zig"),
|
||||||
|
.target = target,
|
||||||
|
.optimize = optimize,
|
||||||
|
}));
|
||||||
|
} else {
|
||||||
const miclib = b.lazyDependency("miclib", .{
|
const miclib = b.lazyDependency("miclib", .{
|
||||||
.target = target,
|
.target = target,
|
||||||
.optimize = optimize,
|
.optimize = optimize,
|
||||||
@@ -546,6 +540,7 @@ fn customPhi(
|
|||||||
}) orelse return error.UnresolvedDependency;
|
}) orelse return error.UnresolvedDependency;
|
||||||
|
|
||||||
lib_mod.addImport("miclib", miclib.module("miclib"));
|
lib_mod.addImport("miclib", miclib.module("miclib"));
|
||||||
|
}
|
||||||
|
|
||||||
const phi_protocol_c = b.addTranslateC(.{
|
const phi_protocol_c = b.addTranslateC(.{
|
||||||
.root_source_file = b.path("src/phi/shared/Protocol.h"),
|
.root_source_file = b.path("src/phi/shared/Protocol.h"),
|
||||||
@@ -556,20 +551,10 @@ fn customPhi(
|
|||||||
|
|
||||||
lib_mod.addImport("phi_protocol_c", phi_protocol_c.createModule());
|
lib_mod.addImport("phi_protocol_c", phi_protocol_c.createModule());
|
||||||
|
|
||||||
// To avoid duplicated options due to Ape's custom function
|
|
||||||
if (!std.mem.eql(u8, lib.name, "vulkan_phi")) {
|
|
||||||
const daemon = try addPhiCardDaemon(b, optimize, "k1om-mpss-linux-gcc", null);
|
|
||||||
const embedded_daemon = addEmbeddedPhiDaemon(b, daemon);
|
|
||||||
lib_mod.addAnonymousImport("phi_daemon", .{
|
|
||||||
.root_source_file = embedded_daemon,
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const build_card = b.option(
|
const build_card = b.option(
|
||||||
bool,
|
bool,
|
||||||
"phi-build-daemon",
|
"phi-build-daemon",
|
||||||
"Build Xeon Phi card daemon",
|
"Build the Phi device daemon",
|
||||||
) orelse true;
|
) orelse true;
|
||||||
|
|
||||||
if (!build_card)
|
if (!build_card)
|
||||||
@@ -587,8 +572,11 @@ fn customPhi(
|
|||||||
"MPSS sysroot path",
|
"MPSS sysroot path",
|
||||||
);
|
);
|
||||||
|
|
||||||
const daemon = try addPhiCardDaemon(b, optimize, cc, sysroot);
|
const daemon = try addPhiDaemon(b, optimize, host_emulation, emulation_port, cc, sysroot);
|
||||||
const install_daemon = b.addInstallFile(daemon, "lib/phi_device.mic");
|
const install_daemon = b.addInstallFile(
|
||||||
|
daemon,
|
||||||
|
if (host_emulation) "bin/phi_device-host" else "lib/phi_device.mic",
|
||||||
|
);
|
||||||
lib.step.dependOn(&install_daemon.step);
|
lib.step.dependOn(&install_daemon.step);
|
||||||
|
|
||||||
const embedded_daemon = addEmbeddedPhiDaemon(b, daemon);
|
const embedded_daemon = addEmbeddedPhiDaemon(b, daemon);
|
||||||
@@ -597,24 +585,17 @@ fn customPhi(
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn optionsPhi(b: *std.Build, options: *Step.Options) !void {
|
fn addPhiDaemon(
|
||||||
const daemon_remote_path = b.option(
|
b: *std.Build,
|
||||||
[]const u8,
|
optimize: std.builtin.OptimizeMode,
|
||||||
"phi-daemon-remote-path",
|
host_emulation: bool,
|
||||||
"Path where the Xeon Phi daemon is copied on the card",
|
emulation_port: u16,
|
||||||
) orelse "/tmp/phi_device.mic";
|
cc: []const u8,
|
||||||
|
sysroot: ?[]const u8,
|
||||||
|
) !std.Build.LazyPath {
|
||||||
|
if (host_emulation)
|
||||||
|
return addPhiHostDaemon(b, optimize, emulation_port);
|
||||||
|
|
||||||
const daemon_host_prefix = b.option(
|
|
||||||
[]const u8,
|
|
||||||
"phi-daemon-host-prefix",
|
|
||||||
"Host prefix used to reach cards over ssh/scp; card N uses <prefix>N",
|
|
||||||
) orelse "mic";
|
|
||||||
|
|
||||||
options.addOption([]const u8, "phi_daemon_remote_path", daemon_remote_path);
|
|
||||||
options.addOption([]const u8, "phi_daemon_host_prefix", daemon_host_prefix);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn addPhiCardDaemon(b: *std.Build, optimize: std.builtin.OptimizeMode, cc: []const u8, sysroot: ?[]const u8) !std.Build.LazyPath {
|
|
||||||
const cmd = b.addSystemCommand(&.{cc});
|
const cmd = b.addSystemCommand(&.{cc});
|
||||||
|
|
||||||
cmd.addArgs(&.{
|
cmd.addArgs(&.{
|
||||||
@@ -649,6 +630,7 @@ fn addPhiCardDaemon(b: *std.Build, optimize: std.builtin.OptimizeMode, cc: []con
|
|||||||
"src/phi/mic/Daemon.c",
|
"src/phi/mic/Daemon.c",
|
||||||
"src/phi/mic/Logger.c",
|
"src/phi/mic/Logger.c",
|
||||||
"src/phi/mic/Memory.c",
|
"src/phi/mic/Memory.c",
|
||||||
|
"src/phi/mic/Transport.c",
|
||||||
// Add new files here
|
// Add new files here
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -656,14 +638,46 @@ fn addPhiCardDaemon(b: *std.Build, optimize: std.builtin.OptimizeMode, cc: []con
|
|||||||
cmd.addFileArg(b.path(source));
|
cmd.addFileArg(b.path(source));
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd.addArgs(&.{
|
cmd.addArgs(&.{ "-lscif", "-o" });
|
||||||
"-lscif",
|
|
||||||
"-o",
|
|
||||||
});
|
|
||||||
|
|
||||||
return cmd.addOutputFileArg("phi_device.mic");
|
return cmd.addOutputFileArg("phi_device.mic");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn addPhiHostDaemon(b: *std.Build, optimize: std.builtin.OptimizeMode, emulation_port: u16) std.Build.LazyPath {
|
||||||
|
const daemon_mod = b.createModule(.{
|
||||||
|
.target = b.graph.host,
|
||||||
|
.optimize = optimize,
|
||||||
|
.link_libc = true,
|
||||||
|
});
|
||||||
|
daemon_mod.addIncludePath(b.path("src/phi/mic"));
|
||||||
|
daemon_mod.addIncludePath(b.path("src/phi/shared"));
|
||||||
|
daemon_mod.addCMacro("PHI_HOST_EMULATION", "1");
|
||||||
|
daemon_mod.addCMacro("PHI_TRANSPORT_PORT", b.fmt("{d}", .{emulation_port}));
|
||||||
|
daemon_mod.addCSourceFiles(.{
|
||||||
|
.files = &.{
|
||||||
|
"src/phi/mic/main.c",
|
||||||
|
"src/phi/mic/Buffer.c",
|
||||||
|
"src/phi/mic/CommandBuffer.c",
|
||||||
|
"src/phi/mic/Daemon.c",
|
||||||
|
"src/phi/mic/Logger.c",
|
||||||
|
"src/phi/mic/Memory.c",
|
||||||
|
"src/phi/mic/Transport.c",
|
||||||
|
},
|
||||||
|
.flags = &.{
|
||||||
|
"-std=c11",
|
||||||
|
"-Wall",
|
||||||
|
"-Wextra",
|
||||||
|
"-Wno-unused-parameter",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
daemon_mod.linkSystemLibrary("pthread", .{});
|
||||||
|
|
||||||
|
const daemon = b.addExecutable(.{
|
||||||
|
.name = "phi_device-host",
|
||||||
|
.root_module = daemon_mod,
|
||||||
|
});
|
||||||
|
return daemon.getEmittedBin();
|
||||||
|
}
|
||||||
|
|
||||||
fn addEmbeddedPhiDaemon(b: *std.Build, daemon: std.Build.LazyPath) std.Build.LazyPath {
|
fn addEmbeddedPhiDaemon(b: *std.Build, daemon: std.Build.LazyPath) std.Build.LazyPath {
|
||||||
const wf = b.addWriteFiles();
|
const wf = b.addWriteFiles();
|
||||||
_ = wf.addCopyFile(daemon, "phi_device.mic");
|
_ = wf.addCopyFile(daemon, "phi_device.mic");
|
||||||
|
|||||||
+35
-1
@@ -81,7 +81,10 @@ pub fn create(instance: *base.Instance, physical_device: *base.PhysicalDevice, a
|
|||||||
const phi_physical_device: *PhiPhysicalDevice = @alignCast(@fieldParentPtr("interface", physical_device));
|
const phi_physical_device: *PhiPhysicalDevice = @alignCast(@fieldParentPtr("interface", physical_device));
|
||||||
|
|
||||||
const transport = PhiTransport.init(instance, phi_physical_device.scif_node_id) catch blk: {
|
const transport = PhiTransport.init(instance, phi_physical_device.scif_node_id) catch blk: {
|
||||||
// If the first connection failed, upload and launch the daemon on the card.
|
// If the first connection failed, launch the daemon on the selected device.
|
||||||
|
if (comptime config.phi_host_emulation)
|
||||||
|
try launchHostDaemon(instance, allocator)
|
||||||
|
else
|
||||||
try uploadAndLaunchDaemon(instance, allocator, phi_physical_device.mic_device_num);
|
try uploadAndLaunchDaemon(instance, allocator, phi_physical_device.mic_device_num);
|
||||||
|
|
||||||
const max_connect_attempts = 3;
|
const max_connect_attempts = 3;
|
||||||
@@ -242,6 +245,37 @@ pub fn getDeviceGroupSurfacePresentModesKHR(_: *Interface, _: *base.SurfaceKHR)
|
|||||||
return .{ .local_bit_khr = true };
|
return .{ .local_bit_khr = true };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn launchHostDaemon(instance: *base.Instance, allocator: std.mem.Allocator) VkError!void {
|
||||||
|
const io = instance.io();
|
||||||
|
const process_id = std.os.linux.getpid();
|
||||||
|
const thread_id = std.Thread.getCurrentId();
|
||||||
|
|
||||||
|
const local_path = std.fmt.allocPrint(allocator, "/tmp/ape_phi_device_{d}_{d}.host", .{ process_id, thread_id }) catch return VkError.OutOfHostMemory;
|
||||||
|
defer allocator.free(local_path);
|
||||||
|
errdefer std.Io.Dir.deleteFileAbsolute(io, local_path) catch {};
|
||||||
|
|
||||||
|
std.Io.Dir.writeFile(.cwd(), io, .{
|
||||||
|
.sub_path = local_path,
|
||||||
|
.data = daemon_binary,
|
||||||
|
}) catch |err| {
|
||||||
|
std.log.scoped(.PhiDevice).err("Failed to write embedded Phi host daemon: {s}", .{@errorName(err)});
|
||||||
|
return VkError.InitializationFailed;
|
||||||
|
};
|
||||||
|
|
||||||
|
const launch_command = std.fmt.allocPrint(
|
||||||
|
allocator,
|
||||||
|
"chmod +x {s} && (nohup {s} --unlink-on-start >/tmp/phi_device_host.log 2>&1 </dev/null &)",
|
||||||
|
.{ local_path, local_path },
|
||||||
|
) catch return VkError.OutOfHostMemory;
|
||||||
|
defer allocator.free(launch_command);
|
||||||
|
|
||||||
|
std.log.scoped(.PhiDevice).debug(
|
||||||
|
"Launching Phi host daemon on 127.0.0.1:{d}",
|
||||||
|
.{config.phi_emulation_port},
|
||||||
|
);
|
||||||
|
try runHostCommand(instance, allocator, &.{ "sh", "-c", launch_command });
|
||||||
|
}
|
||||||
|
|
||||||
fn uploadAndLaunchDaemon(instance: *base.Instance, allocator: std.mem.Allocator, mic_device_num: u32) VkError!void {
|
fn uploadAndLaunchDaemon(instance: *base.Instance, allocator: std.mem.Allocator, mic_device_num: u32) VkError!void {
|
||||||
const io = instance.io();
|
const io = instance.io();
|
||||||
const process_id = std.os.linux.getpid();
|
const process_id = std.os.linux.getpid();
|
||||||
|
|||||||
@@ -61,6 +61,7 @@ fn destroy(interface: *Interface, allocator: std.mem.Allocator) VkError!void {
|
|||||||
self.threaded.deinit();
|
self.threaded.deinit();
|
||||||
allocator.destroy(self);
|
allocator.destroy(self);
|
||||||
|
|
||||||
|
if (comptime !lib.config.phi_host_emulation)
|
||||||
mic.unload();
|
mic.unload();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -69,6 +70,17 @@ fn requestPhysicalDevices(interface: *Interface, allocator: std.mem.Allocator, _
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (comptime lib.config.phi_host_emulation) {
|
||||||
|
const physical_device = try PhiPhysicalDevice.createEmulated(allocator, interface);
|
||||||
|
errdefer physical_device.interface.release(allocator) catch @panic("Caught an error while handling an error");
|
||||||
|
|
||||||
|
const dispatchable = try Dispatchable(base.PhysicalDevice).wrap(allocator, &physical_device.interface);
|
||||||
|
errdefer dispatchable.destroy(allocator);
|
||||||
|
|
||||||
|
interface.physical_devices.append(allocator, dispatchable) catch return VkError.OutOfHostMemory;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
mic.load() catch |err| {
|
mic.load() catch |err| {
|
||||||
std.log.scoped(.MIC).err("Failed to load libmicmgmt: {s}", .{@errorName(err)});
|
std.log.scoped(.MIC).err("Failed to load libmicmgmt: {s}", .{@errorName(err)});
|
||||||
return VkError.InitializationFailed;
|
return VkError.InitializationFailed;
|
||||||
|
|||||||
@@ -34,6 +34,21 @@ scif_node_id: u16,
|
|||||||
mic_device_num: u32,
|
mic_device_num: u32,
|
||||||
|
|
||||||
pub fn create(allocator: std.mem.Allocator, instance: *base.Instance, mic_device: mic.Device, mic_device_num: u32) VkError!*Self {
|
pub fn create(allocator: std.mem.Allocator, instance: *base.Instance, mic_device: mic.Device, mic_device_num: u32) VkError!*Self {
|
||||||
|
if (comptime lib.config.phi_host_emulation) {
|
||||||
|
return VkError.InitializationFailed;
|
||||||
|
} else {
|
||||||
|
return createInternal(allocator, instance, mic_device, mic_device_num);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn createEmulated(allocator: std.mem.Allocator, instance: *base.Instance) VkError!*Self {
|
||||||
|
if (comptime lib.config.phi_host_emulation)
|
||||||
|
return createInternal(allocator, instance, null, 0)
|
||||||
|
else
|
||||||
|
return VkError.InitializationFailed;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn createInternal(allocator: std.mem.Allocator, instance: *base.Instance, mic_device: ?mic.Device, mic_device_num: u32) VkError!*Self {
|
||||||
const self = allocator.create(Self) catch return VkError.OutOfHostMemory;
|
const self = allocator.create(Self) catch return VkError.OutOfHostMemory;
|
||||||
errdefer allocator.destroy(self);
|
errdefer allocator.destroy(self);
|
||||||
|
|
||||||
@@ -61,7 +76,14 @@ pub fn create(allocator: std.mem.Allocator, instance: *base.Instance, mic_device
|
|||||||
|
|
||||||
@memset(interface.props.device_name[0..], 0);
|
@memset(interface.props.device_name[0..], 0);
|
||||||
|
|
||||||
if (mic_device.pciConfig()) |pci_value| {
|
if (comptime lib.config.phi_host_emulation) {
|
||||||
|
interface.props.vendor_id = 0x8086;
|
||||||
|
interface.props.device_id = 0x2250;
|
||||||
|
const name = "Intel(R) Xeon Phi(TM) Coprocessor Host Emulation [Phi ApeDriver]";
|
||||||
|
@memcpy(interface.props.device_name[0..name.len], name);
|
||||||
|
} else {
|
||||||
|
const device = mic_device.?;
|
||||||
|
if (device.pciConfig()) |pci_value| {
|
||||||
var pci = pci_value;
|
var pci = pci_value;
|
||||||
defer pci.deinit();
|
defer pci.deinit();
|
||||||
|
|
||||||
@@ -85,6 +107,7 @@ pub fn create(allocator: std.mem.Allocator, instance: *base.Instance, mic_device
|
|||||||
std.log.scoped(.MIC).err("Failed to fetch device PCI config: {s}", .{@errorName(err)});
|
std.log.scoped(.MIC).err("Failed to fetch device PCI config: {s}", .{@errorName(err)});
|
||||||
return VkError.InitializationFailed;
|
return VkError.InitializationFailed;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
interface.props.pipeline_cache_uuid = @splat(0);
|
interface.props.pipeline_cache_uuid = @splat(0);
|
||||||
interface.props.limits = .{
|
interface.props.limits = .{
|
||||||
@@ -224,24 +247,31 @@ pub fn create(allocator: std.mem.Allocator, instance: *base.Instance, mic_device
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mic_device.memoryInfo()) |memory_value| {
|
interface.mem_props.memory_heap_count = 2;
|
||||||
|
if (comptime lib.config.phi_host_emulation) {
|
||||||
|
interface.mem_props.memory_heaps[0] = .{
|
||||||
|
.size = std.process.totalSystemMemory() catch 0,
|
||||||
|
.flags = .{ .device_local_bit = true },
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
const device = mic_device.?;
|
||||||
|
if (device.memoryInfo()) |memory_value| {
|
||||||
var memory = memory_value;
|
var memory = memory_value;
|
||||||
defer memory.deinit();
|
defer memory.deinit();
|
||||||
|
|
||||||
interface.mem_props.memory_heap_count = 2;
|
|
||||||
|
|
||||||
interface.mem_props.memory_heaps[0] = .{
|
interface.mem_props.memory_heaps[0] = .{
|
||||||
.size = memory.size() catch 0,
|
.size = memory.size() catch 0,
|
||||||
.flags = .{ .device_local_bit = true },
|
.flags = .{ .device_local_bit = true },
|
||||||
};
|
};
|
||||||
interface.mem_props.memory_heaps[1] = .{
|
|
||||||
.size = std.process.totalSystemMemory() catch 0,
|
|
||||||
.flags = .{},
|
|
||||||
};
|
|
||||||
} else |err| {
|
} else |err| {
|
||||||
std.log.scoped(.MIC).err("Failed to fetch device memory infos: {s}", .{@errorName(err)});
|
std.log.scoped(.MIC).err("Failed to fetch device memory infos: {s}", .{@errorName(err)});
|
||||||
return VkError.InitializationFailed;
|
return VkError.InitializationFailed;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
interface.mem_props.memory_heaps[1] = .{
|
||||||
|
.size = std.process.totalSystemMemory() catch 0,
|
||||||
|
.flags = .{},
|
||||||
|
};
|
||||||
|
|
||||||
interface.features = .{
|
interface.features = .{
|
||||||
.shader_float_64 = .true,
|
.shader_float_64 = .true,
|
||||||
|
|||||||
@@ -5,34 +5,55 @@ const scif = @import("scif.zig");
|
|||||||
|
|
||||||
const VkError = base.VkError;
|
const VkError = base.VkError;
|
||||||
const proto = lib.proto;
|
const proto = lib.proto;
|
||||||
|
const Endpoint = if (lib.config.phi_host_emulation) std.Io.net.Stream else scif.epd_t;
|
||||||
|
|
||||||
const Self = @This();
|
const Self = @This();
|
||||||
|
|
||||||
epd: scif.epd_t,
|
epd: Endpoint,
|
||||||
sequence: u64 = 1,
|
sequence: u64 = 1,
|
||||||
mutex: std.Io.Mutex = .init,
|
mutex: std.Io.Mutex = .init,
|
||||||
instance: *base.Instance,
|
instance: *base.Instance,
|
||||||
|
|
||||||
pub fn init(instance: *base.Instance, node_id: u16) VkError!Self {
|
pub fn init(instance: *base.Instance, node_id: u16) VkError!Self {
|
||||||
|
const epd = if (comptime lib.config.phi_host_emulation) blk: {
|
||||||
|
const address: std.Io.net.IpAddress = .{
|
||||||
|
.ip4 = .loopback(lib.config.phi_emulation_port),
|
||||||
|
};
|
||||||
|
const stream = address.connect(instance.io(), .{ .mode = .stream }) catch |err| {
|
||||||
|
std.log.scoped(.PhiTransport).err(
|
||||||
|
"TCP connection to 127.0.0.1:{d} failed: {s}",
|
||||||
|
.{ lib.config.phi_emulation_port, @errorName(err) },
|
||||||
|
);
|
||||||
|
return VkError.InitializationFailed;
|
||||||
|
};
|
||||||
|
break :blk stream;
|
||||||
|
} else blk: {
|
||||||
try scif.load();
|
try scif.load();
|
||||||
errdefer scif.unload();
|
errdefer scif.unload();
|
||||||
|
|
||||||
const epd = scif.open();
|
const endpoint = scif.open();
|
||||||
if (epd < 0) {
|
if (endpoint < 0) {
|
||||||
std.log.scoped(.PhiTransport).err("SCIF open failed", .{});
|
std.log.scoped(.PhiTransport).err("SCIF open failed", .{});
|
||||||
return VkError.InitializationFailed;
|
return VkError.InitializationFailed;
|
||||||
}
|
}
|
||||||
errdefer _ = scif.close(epd);
|
errdefer _ = scif.close(endpoint);
|
||||||
|
|
||||||
var dst: scif.PortId = .{
|
var dst: scif.PortId = .{
|
||||||
.node = node_id,
|
.node = node_id,
|
||||||
.port = @intCast(proto.PHI_SCIF_PORT),
|
.port = @intCast(proto.PHI_SCIF_PORT),
|
||||||
};
|
};
|
||||||
|
|
||||||
if (scif.connect(epd, &dst) < 0) {
|
if (scif.connect(endpoint, &dst) < 0) {
|
||||||
std.log.scoped(.PhiTransport).err("SCIF connection to node {d} port {d} failed", .{ dst.node, dst.port });
|
std.log.scoped(.PhiTransport).err("SCIF connection to node {d} port {d} failed", .{ dst.node, dst.port });
|
||||||
return VkError.InitializationFailed;
|
return VkError.InitializationFailed;
|
||||||
}
|
}
|
||||||
|
break :blk endpoint;
|
||||||
|
};
|
||||||
|
errdefer {
|
||||||
|
closeEndpoint(epd, instance.io());
|
||||||
|
if (comptime !lib.config.phi_host_emulation)
|
||||||
|
scif.unload();
|
||||||
|
}
|
||||||
|
|
||||||
var self: Self = .{
|
var self: Self = .{
|
||||||
.epd = epd,
|
.epd = epd,
|
||||||
@@ -50,7 +71,8 @@ pub fn deinit(self: *Self) void {
|
|||||||
std.log.scoped(.PhiTransport).warn("Failed to shut down remote session: {s}", .{@errorName(err)});
|
std.log.scoped(.PhiTransport).warn("Failed to shut down remote session: {s}", .{@errorName(err)});
|
||||||
};
|
};
|
||||||
|
|
||||||
_ = scif.close(self.epd);
|
closeEndpoint(self.epd, self.instance.io());
|
||||||
|
if (comptime !lib.config.phi_host_emulation)
|
||||||
scif.unload();
|
scif.unload();
|
||||||
std.log.scoped(.PhiTransport).info("Closed connection", .{});
|
std.log.scoped(.PhiTransport).info("Closed connection", .{});
|
||||||
}
|
}
|
||||||
@@ -99,6 +121,16 @@ pub fn statusToErr(status: c_int) VkError {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn writeAll(self: *Self, bytes: []const u8) VkError!void {
|
fn writeAll(self: *Self, bytes: []const u8) VkError!void {
|
||||||
|
if (comptime lib.config.phi_host_emulation) {
|
||||||
|
var buffer: [0]u8 = .{};
|
||||||
|
var writer = self.epd.writer(self.instance.io(), &buffer);
|
||||||
|
writer.interface.writeAll(bytes) catch |err| {
|
||||||
|
std.log.scoped(.PhiTransport).err("TCP send failed: {s}", .{@errorName(err)});
|
||||||
|
return VkError.InitializationFailed;
|
||||||
|
};
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
var offset: usize = 0;
|
var offset: usize = 0;
|
||||||
while (offset < bytes.len) {
|
while (offset < bytes.len) {
|
||||||
const written = scif.send(self.epd, bytes[offset..].ptr, bytes.len - offset, scif.send_block);
|
const written = scif.send(self.epd, bytes[offset..].ptr, bytes.len - offset, scif.send_block);
|
||||||
@@ -110,6 +142,16 @@ fn writeAll(self: *Self, bytes: []const u8) VkError!void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn readAll(self: *Self, bytes: []u8) VkError!void {
|
fn readAll(self: *Self, bytes: []u8) VkError!void {
|
||||||
|
if (comptime lib.config.phi_host_emulation) {
|
||||||
|
var buffer: [0]u8 = .{};
|
||||||
|
var reader = self.epd.reader(self.instance.io(), &buffer);
|
||||||
|
reader.interface.readSliceAll(bytes) catch |err| {
|
||||||
|
std.log.scoped(.PhiTransport).err("TCP receive failed: {s}", .{@errorName(err)});
|
||||||
|
return VkError.InitializationFailed;
|
||||||
|
};
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
var offset: usize = 0;
|
var offset: usize = 0;
|
||||||
while (offset < bytes.len) {
|
while (offset < bytes.len) {
|
||||||
const read = scif.recv(self.epd, bytes[offset..].ptr, bytes.len - offset, scif.recv_block);
|
const read = scif.recv(self.epd, bytes[offset..].ptr, bytes.len - offset, scif.recv_block);
|
||||||
@@ -120,6 +162,13 @@ fn readAll(self: *Self, bytes: []u8) VkError!void {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn closeEndpoint(endpoint: Endpoint, io: std.Io) void {
|
||||||
|
if (comptime lib.config.phi_host_emulation)
|
||||||
|
endpoint.close(io)
|
||||||
|
else
|
||||||
|
_ = scif.close(endpoint);
|
||||||
|
}
|
||||||
|
|
||||||
fn handshake(self: *Self) VkError!void {
|
fn handshake(self: *Self) VkError!void {
|
||||||
const request_payload: proto.PhiHelloRequest = .{
|
const request_payload: proto.PhiHelloRequest = .{
|
||||||
.host_protocol_version = proto.PHI_PROTOCOL_VERSION,
|
.host_protocol_version = proto.PHI_PROTOCOL_VERSION,
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ static PhiStatus ExecuteCommand(PhiCommandReader* reader, const PhiCmdHeader* co
|
|||||||
return PHI_STATUS_BAD_MESSAGE;
|
return PHI_STATUS_BAD_MESSAGE;
|
||||||
}
|
}
|
||||||
|
|
||||||
int HandleWorkExecution(scif_epd_t endpoint, const PhiMessageHeader* header)
|
int HandleWorkExecution(PhiEndpoint endpoint, const PhiMessageHeader* header)
|
||||||
{
|
{
|
||||||
PhiWorkExecutionRequest request;
|
PhiWorkExecutionRequest request;
|
||||||
PhiWorkExecutionReply reply = {
|
PhiWorkExecutionReply reply = {
|
||||||
|
|||||||
@@ -5,11 +5,11 @@
|
|||||||
|
|
||||||
typedef struct PhiCommandReader
|
typedef struct PhiCommandReader
|
||||||
{
|
{
|
||||||
scif_epd_t endpoint;
|
PhiEndpoint endpoint;
|
||||||
uint64_t remaining;
|
uint64_t remaining;
|
||||||
} PhiCommandReader;
|
} PhiCommandReader;
|
||||||
|
|
||||||
int HandleWorkExecution(scif_epd_t endpoint, const PhiMessageHeader* header);
|
int HandleWorkExecution(PhiEndpoint endpoint, const PhiMessageHeader* header);
|
||||||
int PhiDrainCommandReader(PhiCommandReader* reader);
|
int PhiDrainCommandReader(PhiCommandReader* reader);
|
||||||
PhiStatus PhiReadCommandData(PhiCommandReader* reader, void* data, uint64_t size);
|
PhiStatus PhiReadCommandData(PhiCommandReader* reader, void* data, uint64_t size);
|
||||||
|
|
||||||
|
|||||||
+17
-33
@@ -3,7 +3,7 @@
|
|||||||
#include <Logger.h>
|
#include <Logger.h>
|
||||||
#include <Memory.h>
|
#include <Memory.h>
|
||||||
|
|
||||||
static int HandleHello(scif_epd_t endpoint, const PhiMessageHeader* header)
|
static int HandleHello(PhiEndpoint endpoint, const PhiMessageHeader* header)
|
||||||
{
|
{
|
||||||
PhiHelloRequest request;
|
PhiHelloRequest request;
|
||||||
PhiHelloReply reply = {
|
PhiHelloReply reply = {
|
||||||
@@ -32,41 +32,25 @@ static int HandleHello(scif_epd_t endpoint, const PhiMessageHeader* header)
|
|||||||
return SendReply(endpoint, header, &reply, sizeof(reply));
|
return SendReply(endpoint, header, &reply, sizeof(reply));
|
||||||
}
|
}
|
||||||
|
|
||||||
scif_epd_t StartDaemon()
|
PhiEndpoint StartDaemon(void)
|
||||||
{
|
{
|
||||||
PhiLogInfo("Starting the daemon...");
|
PhiLogInfo("Starting the daemon...");
|
||||||
|
|
||||||
scif_epd_t endpoint = scif_open();
|
PhiEndpoint endpoint = PhiTransportListen(PHI_TRANSPORT_PORT);
|
||||||
if(endpoint < 0)
|
if(endpoint == PHI_ENDPOINT_INVALID)
|
||||||
{
|
PhiLogError("Could not listen on the Phi transport");
|
||||||
PhiLogError("Failed to create SCIF endpoint");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(scif_bind(endpoint, PHI_SCIF_PORT) < 0)
|
|
||||||
{
|
|
||||||
PhiLogError("Failed to bind SCIF port");
|
|
||||||
scif_close(endpoint);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(scif_listen(endpoint, 16) < 0)
|
|
||||||
{
|
|
||||||
PhiLogError("Could not listen to SCIF port");
|
|
||||||
scif_close(endpoint);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
PhiLogInfo("Daemon started");
|
||||||
return endpoint;
|
return endpoint;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ShutdownDaemon(scif_epd_t endpoint)
|
void ShutdownDaemon(PhiEndpoint endpoint)
|
||||||
{
|
{
|
||||||
PhiLogInfo("Shuting down the daemon...");
|
PhiLogInfo("Shutting down the daemon...");
|
||||||
scif_close(endpoint);
|
PhiTransportClose(endpoint);
|
||||||
}
|
}
|
||||||
|
|
||||||
int HandlePacket(scif_epd_t endpoint)
|
int HandlePacket(PhiEndpoint endpoint)
|
||||||
{
|
{
|
||||||
for(;;)
|
for(;;)
|
||||||
{
|
{
|
||||||
@@ -123,14 +107,14 @@ int HandlePacket(scif_epd_t endpoint)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int ReadAll(scif_epd_t endpoint, void* data, size_t size)
|
int ReadAll(PhiEndpoint endpoint, void* data, size_t size)
|
||||||
{
|
{
|
||||||
uint8_t* bytes = data;
|
uint8_t* bytes = data;
|
||||||
size_t offset = 0;
|
size_t offset = 0;
|
||||||
|
|
||||||
while(offset < size)
|
while(offset < size)
|
||||||
{
|
{
|
||||||
int got = scif_recv(endpoint, bytes + offset, size - offset, SCIF_RECV_BLOCK);
|
ssize_t got = PhiTransportReceive(endpoint, bytes + offset, size - offset);
|
||||||
if(got <= 0)
|
if(got <= 0)
|
||||||
return -1;
|
return -1;
|
||||||
offset += (size_t)got;
|
offset += (size_t)got;
|
||||||
@@ -139,14 +123,14 @@ int ReadAll(scif_epd_t endpoint, void* data, size_t size)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int WriteAll(scif_epd_t endpoint, const void* data, size_t size)
|
int WriteAll(PhiEndpoint endpoint, const void* data, size_t size)
|
||||||
{
|
{
|
||||||
const uint8_t* bytes = data;
|
const uint8_t* bytes = data;
|
||||||
size_t offset = 0;
|
size_t offset = 0;
|
||||||
|
|
||||||
while(offset < size)
|
while(offset < size)
|
||||||
{
|
{
|
||||||
int sent = scif_send(endpoint, (void*)(bytes + offset), size - offset, SCIF_SEND_BLOCK);
|
ssize_t sent = PhiTransportSend(endpoint, bytes + offset, size - offset);
|
||||||
if(sent <= 0)
|
if(sent <= 0)
|
||||||
return -1;
|
return -1;
|
||||||
offset += (size_t)sent;
|
offset += (size_t)sent;
|
||||||
@@ -155,7 +139,7 @@ int WriteAll(scif_epd_t endpoint, const void* data, size_t size)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int SendReply(scif_epd_t endpoint, const PhiMessageHeader* request, const void* payload, uint64_t payload_size)
|
int SendReply(PhiEndpoint endpoint, const PhiMessageHeader* request, const void* payload, uint64_t payload_size)
|
||||||
{
|
{
|
||||||
PhiMessageHeader reply = {
|
PhiMessageHeader reply = {
|
||||||
.magic = PHI_PROTOCOL_MAGIC,
|
.magic = PHI_PROTOCOL_MAGIC,
|
||||||
@@ -171,7 +155,7 @@ int SendReply(scif_epd_t endpoint, const PhiMessageHeader* request, const void*
|
|||||||
return WriteAll(endpoint, payload, (size_t)payload_size);
|
return WriteAll(endpoint, payload, (size_t)payload_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
int SendStatus(scif_epd_t endpoint, const PhiMessageHeader* request, PhiStatus status)
|
int SendStatus(PhiEndpoint endpoint, const PhiMessageHeader* request, PhiStatus status)
|
||||||
{
|
{
|
||||||
PhiFreeMemoryReply reply = {
|
PhiFreeMemoryReply reply = {
|
||||||
.result = {
|
.result = {
|
||||||
@@ -183,7 +167,7 @@ int SendStatus(scif_epd_t endpoint, const PhiMessageHeader* request, PhiStatus s
|
|||||||
return SendReply(endpoint, request, &reply, sizeof(reply));
|
return SendReply(endpoint, request, &reply, sizeof(reply));
|
||||||
}
|
}
|
||||||
|
|
||||||
int DrainPayload(scif_epd_t endpoint, uint64_t size)
|
int DrainPayload(PhiEndpoint endpoint, uint64_t size)
|
||||||
{
|
{
|
||||||
uint8_t buffer[256];
|
uint8_t buffer[256];
|
||||||
|
|
||||||
|
|||||||
+9
-10
@@ -3,18 +3,17 @@
|
|||||||
|
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
|
||||||
#include <scif.h>
|
|
||||||
|
|
||||||
#include <Protocol.h>
|
#include <Protocol.h>
|
||||||
|
#include <Transport.h>
|
||||||
|
|
||||||
scif_epd_t StartDaemon();
|
PhiEndpoint StartDaemon(void);
|
||||||
void ShutdownDaemon(scif_epd_t endpoint);
|
void ShutdownDaemon(PhiEndpoint endpoint);
|
||||||
|
|
||||||
int DrainPayload(scif_epd_t endpoint, uint64_t size);
|
int DrainPayload(PhiEndpoint endpoint, uint64_t size);
|
||||||
int HandlePacket(scif_epd_t endpoint);
|
int HandlePacket(PhiEndpoint endpoint);
|
||||||
int ReadAll(scif_epd_t endpoint, void* data, size_t size);
|
int ReadAll(PhiEndpoint endpoint, void* data, size_t size);
|
||||||
int SendReply(scif_epd_t endpoint, const PhiMessageHeader* request, const void* payload, uint64_t payload_size);
|
int SendReply(PhiEndpoint endpoint, const PhiMessageHeader* request, const void* payload, uint64_t payload_size);
|
||||||
int SendStatus(scif_epd_t endpoint, const PhiMessageHeader* request, PhiStatus status);
|
int SendStatus(PhiEndpoint endpoint, const PhiMessageHeader* request, PhiStatus status);
|
||||||
int WriteAll(scif_epd_t endpoint, const void* data, size_t size);
|
int WriteAll(PhiEndpoint endpoint, const void* data, size_t size);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -84,6 +84,7 @@ void PhiLog(PhiLogLevel level, const char* fmt, const char* file, const char* fu
|
|||||||
va_end(argptr);
|
va_end(argptr);
|
||||||
|
|
||||||
fputc('\n', out);
|
fputc('\n', out);
|
||||||
|
fflush(out);
|
||||||
|
|
||||||
if(level == PHI_LOG_LEVEL_FATAL)
|
if(level == PHI_LOG_LEVEL_FATAL)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
#include <Logger.h>
|
#include <Logger.h>
|
||||||
#include <Memory.h>
|
#include <Memory.h>
|
||||||
|
|
||||||
int HandleAllocMemory(scif_epd_t endpoint, const PhiMessageHeader* header)
|
int HandleAllocMemory(PhiEndpoint endpoint, const PhiMessageHeader* header)
|
||||||
{
|
{
|
||||||
PhiAllocMemoryRequest request;
|
PhiAllocMemoryRequest request;
|
||||||
PhiAllocMemoryReply reply = {
|
PhiAllocMemoryReply reply = {
|
||||||
@@ -42,7 +42,7 @@ int HandleAllocMemory(scif_epd_t endpoint, const PhiMessageHeader* header)
|
|||||||
return SendReply(endpoint, header, &reply, sizeof(reply));
|
return SendReply(endpoint, header, &reply, sizeof(reply));
|
||||||
}
|
}
|
||||||
|
|
||||||
int HandleFreeMemory(scif_epd_t endpoint, const PhiMessageHeader* header)
|
int HandleFreeMemory(PhiEndpoint endpoint, const PhiMessageHeader* header)
|
||||||
{
|
{
|
||||||
PhiFreeMemoryRequest request;
|
PhiFreeMemoryRequest request;
|
||||||
PhiFreeMemoryReply reply = {
|
PhiFreeMemoryReply reply = {
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
#include <Daemon.h>
|
#include <Daemon.h>
|
||||||
|
|
||||||
int HandleAllocMemory(scif_epd_t endpoint, const PhiMessageHeader* header);
|
int HandleAllocMemory(PhiEndpoint endpoint, const PhiMessageHeader* header);
|
||||||
int HandleFreeMemory(scif_epd_t endpoint, const PhiMessageHeader* header);
|
int HandleFreeMemory(PhiEndpoint endpoint, const PhiMessageHeader* header);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -0,0 +1,109 @@
|
|||||||
|
#include <Transport.h>
|
||||||
|
|
||||||
|
#ifdef PHI_HOST_EMULATION
|
||||||
|
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
static struct sockaddr_in PhiLoopbackAddress(uint16_t port)
|
||||||
|
{
|
||||||
|
struct sockaddr_in address = {
|
||||||
|
.sin_family = AF_INET,
|
||||||
|
.sin_port = htons(port),
|
||||||
|
.sin_addr = {
|
||||||
|
.s_addr = htonl(INADDR_LOOPBACK),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
return address;
|
||||||
|
}
|
||||||
|
|
||||||
|
PhiEndpoint PhiTransportAccept(PhiEndpoint endpoint)
|
||||||
|
{
|
||||||
|
return accept(endpoint, NULL, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
int PhiTransportClose(PhiEndpoint endpoint)
|
||||||
|
{
|
||||||
|
return close(endpoint);
|
||||||
|
}
|
||||||
|
|
||||||
|
PhiEndpoint PhiTransportListen(uint16_t port)
|
||||||
|
{
|
||||||
|
PhiEndpoint endpoint = socket(AF_INET, SOCK_STREAM, 0);
|
||||||
|
if(endpoint == PHI_ENDPOINT_INVALID)
|
||||||
|
return PHI_ENDPOINT_INVALID;
|
||||||
|
|
||||||
|
const int reuse_address = 1;
|
||||||
|
if(setsockopt(endpoint, SOL_SOCKET, SO_REUSEADDR, &reuse_address, sizeof(reuse_address)) < 0)
|
||||||
|
{
|
||||||
|
PhiTransportClose(endpoint);
|
||||||
|
return PHI_ENDPOINT_INVALID;
|
||||||
|
}
|
||||||
|
|
||||||
|
const struct sockaddr_in address = PhiLoopbackAddress(port);
|
||||||
|
if(bind(endpoint, (const struct sockaddr*)&address, sizeof(address)) < 0 || listen(endpoint, 16) < 0)
|
||||||
|
{
|
||||||
|
PhiTransportClose(endpoint);
|
||||||
|
return PHI_ENDPOINT_INVALID;
|
||||||
|
}
|
||||||
|
|
||||||
|
return endpoint;
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t PhiTransportReceive(PhiEndpoint endpoint, void* data, size_t size)
|
||||||
|
{
|
||||||
|
return recv(endpoint, data, size, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t PhiTransportSend(PhiEndpoint endpoint, const void* data, size_t size)
|
||||||
|
{
|
||||||
|
#ifdef MSG_NOSIGNAL
|
||||||
|
return send(endpoint, data, size, MSG_NOSIGNAL);
|
||||||
|
#else
|
||||||
|
return send(endpoint, data, size, 0);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
PhiEndpoint PhiTransportAccept(PhiEndpoint endpoint)
|
||||||
|
{
|
||||||
|
struct scif_portID peer;
|
||||||
|
PhiEndpoint client = PHI_ENDPOINT_INVALID;
|
||||||
|
if(scif_accept(endpoint, &peer, &client, SCIF_ACCEPT_SYNC) < 0)
|
||||||
|
return PHI_ENDPOINT_INVALID;
|
||||||
|
return client;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PhiTransportClose(PhiEndpoint endpoint)
|
||||||
|
{
|
||||||
|
return scif_close(endpoint);
|
||||||
|
}
|
||||||
|
|
||||||
|
PhiEndpoint PhiTransportListen(uint16_t port)
|
||||||
|
{
|
||||||
|
PhiEndpoint endpoint = scif_open();
|
||||||
|
if(endpoint == PHI_ENDPOINT_INVALID)
|
||||||
|
return PHI_ENDPOINT_INVALID;
|
||||||
|
|
||||||
|
if(scif_bind(endpoint, port) < 0 || scif_listen(endpoint, 16) < 0)
|
||||||
|
{
|
||||||
|
PhiTransportClose(endpoint);
|
||||||
|
return PHI_ENDPOINT_INVALID;
|
||||||
|
}
|
||||||
|
return endpoint;
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t PhiTransportReceive(PhiEndpoint endpoint, void* data, size_t size)
|
||||||
|
{
|
||||||
|
return scif_recv(endpoint, data, size, SCIF_RECV_BLOCK);
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t PhiTransportSend(PhiEndpoint endpoint, const void* data, size_t size)
|
||||||
|
{
|
||||||
|
return scif_send(endpoint, (void*)data, size, SCIF_SEND_BLOCK);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
#ifndef APE_PHI_TRANSPORT_H
|
||||||
|
#define APE_PHI_TRANSPORT_H
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
#ifdef PHI_HOST_EMULATION
|
||||||
|
typedef int PhiEndpoint;
|
||||||
|
#else
|
||||||
|
#include <scif.h>
|
||||||
|
typedef scif_epd_t PhiEndpoint;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define PHI_ENDPOINT_INVALID ((PhiEndpoint) - 1)
|
||||||
|
|
||||||
|
PhiEndpoint PhiTransportAccept(PhiEndpoint endpoint);
|
||||||
|
int PhiTransportClose(PhiEndpoint endpoint);
|
||||||
|
|
||||||
|
PhiEndpoint PhiTransportListen(uint16_t port);
|
||||||
|
ssize_t PhiTransportReceive(PhiEndpoint endpoint, void* data, size_t size);
|
||||||
|
ssize_t PhiTransportSend(PhiEndpoint endpoint, const void* data, size_t size);
|
||||||
|
|
||||||
|
#endif
|
||||||
+25
-11
@@ -2,24 +2,37 @@
|
|||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#ifdef PHI_HOST_EMULATION
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <Daemon.h>
|
#include <Daemon.h>
|
||||||
#include <Logger.h>
|
#include <Logger.h>
|
||||||
|
|
||||||
static void* HandleClient(void* const argument)
|
static void* HandleClient(void* const argument)
|
||||||
{
|
{
|
||||||
scif_epd_t client = (scif_epd_t)(intptr_t)argument;
|
PhiEndpoint client = (PhiEndpoint)(intptr_t)argument;
|
||||||
|
|
||||||
(void)HandlePacket(client);
|
(void)HandlePacket(client);
|
||||||
scif_close(client);
|
PhiTransportClose(client);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(void)
|
int main(int argc, char** argv)
|
||||||
{
|
{
|
||||||
scif_epd_t endpoint = StartDaemon();
|
#ifdef PHI_HOST_EMULATION
|
||||||
|
if(argc == 2 && strcmp(argv[1], "--unlink-on-start") == 0)
|
||||||
|
(void)unlink(argv[0]);
|
||||||
|
#else
|
||||||
|
(void)argc;
|
||||||
|
(void)argv;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
PhiEndpoint endpoint = StartDaemon();
|
||||||
pthread_attr_t client_thread_attributes;
|
pthread_attr_t client_thread_attributes;
|
||||||
|
|
||||||
if(endpoint == 0)
|
if(endpoint == PHI_ENDPOINT_INVALID)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
if(pthread_attr_init(&client_thread_attributes) != 0 ||
|
if(pthread_attr_init(&client_thread_attributes) != 0 ||
|
||||||
@@ -32,22 +45,23 @@ int main(void)
|
|||||||
|
|
||||||
for(;;)
|
for(;;)
|
||||||
{
|
{
|
||||||
struct scif_portID peer;
|
PhiEndpoint client = PhiTransportAccept(endpoint);
|
||||||
scif_epd_t client;
|
|
||||||
|
|
||||||
if(scif_accept(endpoint, &peer, &client, SCIF_ACCEPT_SYNC) < 0)
|
if(client == PHI_ENDPOINT_INVALID)
|
||||||
{
|
{
|
||||||
if(errno == EINTR)
|
if(errno == EINTR)
|
||||||
continue;
|
continue;
|
||||||
PhiLogError("Could not accept SCIF connection");
|
PhiLogError("Could not accept transport connection");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PhiLogInfo("Host connected to the daemon");
|
||||||
|
|
||||||
pthread_t client_thread;
|
pthread_t client_thread;
|
||||||
if(pthread_create(&client_thread, &client_thread_attributes, HandleClient, (void*)(intptr_t)client) != 0)
|
if(pthread_create(&client_thread, &client_thread_attributes, HandleClient, (void*)(intptr_t)client) != 0)
|
||||||
{
|
{
|
||||||
PhiLogError("Could not create SCIF client thread");
|
PhiLogError("Could not create transport client thread");
|
||||||
scif_close(client);
|
PhiTransportClose(client);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,3 @@
|
|||||||
|
pub const Device = struct {};
|
||||||
|
|
||||||
|
pub fn unload() void {}
|
||||||
@@ -8,6 +8,10 @@
|
|||||||
#define PHI_PROTOCOL_VERSION 1u
|
#define PHI_PROTOCOL_VERSION 1u
|
||||||
#define PHI_SCIF_PORT 43616u
|
#define PHI_SCIF_PORT 43616u
|
||||||
|
|
||||||
|
#ifndef PHI_TRANSPORT_PORT
|
||||||
|
#define PHI_TRANSPORT_PORT PHI_SCIF_PORT
|
||||||
|
#endif
|
||||||
|
|
||||||
typedef enum PhiPacketType
|
typedef enum PhiPacketType
|
||||||
{
|
{
|
||||||
PHI_PACKET_HELLO = 1,
|
PHI_PACKET_HELLO = 1,
|
||||||
|
|||||||
Reference in New Issue
Block a user