File size: 3,858 Bytes
32b4893
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
(* ========================================================================
 * SOVEREIGN LEVIATHAN NODE LICENSE
 * License-ID: SL-AGPL3-001 | Covenant-Version: 1.0
 * Copyright (C) 2026 SnapKittyWest. Ahmad Ali Parr, Bel Esprit D'Accord Irrevocable Trust.
 * ========================================================================
 *
 * This file is a covered work under the GNU Affero General Public License,
 * version 3, together with the Sovereign Leviathan additional terms.
 *
 * Hark, though this node be but a spark,
 * Its covenant endureth through the dark.
 *
 * Ignorantia juris non excusat.
 * ======================================================================== *)

{ gpu_host.pas
  Pascal host skeleton for launching CUDA kernels via a C shim.
  Free Pascal (FPC) compatible.
  Lines: ~220
}

program GPUHost;

{$mode objfpc}{$H+}

uses
  ctypes, SysUtils;

{ --- Memory manager: simple arena with bookkeeping --- }
type
  PBlock = ^TBlock;
  TBlock = record
    addr: Pointer;
    size: NativeUInt;
    freed: Boolean;
  end;

var
  Blocks: array of PBlock;

procedure register_block(p: Pointer; sz: NativeUInt);
var
  b: PBlock;
begin
  New(b);
  b^.addr := p;
  b^.size := sz;
  b^.freed := False;
  SetLength(Blocks, Length(Blocks) + 1);
  Blocks[High(Blocks)] := b;
end;

function find_block(p: Pointer): Integer;
var
  i: Integer;
begin
  for i := 0 to High(Blocks) do
    if Blocks[i]^.addr = p then Exit(i);
  Result := -1;
end;

procedure check_no_leaks;
var
  i: Integer;
begin
  for i := 0 to High(Blocks) do
    if not Blocks[i]^.freed then
      Writeln('Memory leak: block at ', Blocks[i]^.addr, ' size=', Blocks[i]^.size);
end;

{ --- C shim declarations (must match the C shim below) --- }
type
  TCUResult = cint;

procedure cuda_init; cdecl; external 'libcuda_shim.so';
procedure cuda_finalize; cdecl; external 'libcuda_shim.so';
function cuda_alloc(size: NativeUInt): Pointer; cdecl; external 'libcuda_shim.so';
procedure cuda_free(p: Pointer); cdecl; external 'libcuda_shim.so';
function cuda_launch_vector_add(a_dev, b_dev, c_dev: Pointer; n: cint): TCUResult; cdecl; external 'libcuda_shim.so';

{ --- Pascal wrappers around the C shim --- }
function host_alloc(size: NativeUInt): Pointer;
begin
  Result := cuda_alloc(size);
  if Result = nil then
    raise Exception.Create('cuda_alloc failed');
  register_block(Result, size);
end;

procedure host_free(p: Pointer);
var idx: Integer;
begin
  idx := find_block(p);
  if idx = -1 then
    raise Exception.Create('free: unknown pointer');
  if Blocks[idx]^.freed then
    raise Exception.Create('double free detected');
  Blocks[idx]^.freed := True;
  cuda_free(p);
end;

{ --- Test: vector add on GPU --- }
procedure test_vector_add(n: Integer);
var
  bytes: NativeUInt;
  a_dev, b_dev, c_dev: Pointer;
  i: Integer;
  hostA, hostB, hostC: PSingle;
  res: TCUResult;
begin
  bytes := NativeUInt(n) * SizeOf(Single);
  a_dev := host_alloc(bytes);
  b_dev := host_alloc(bytes);
  c_dev := host_alloc(bytes);

  { prepare host buffers (on CPU) and copy via shim if needed; for simplicity we assume shim provides device alloc only and kernel uses device memory }
  { In a real system, add cuda_memcpy_host_to_device and device_to_host functions }

  res := cuda_launch_vector_add(a_dev, b_dev, c_dev, n);
  if res <> 0 then
    Writeln('Kernel launch failed: ', res)
  else
    Writeln('Kernel launched successfully');

  { cleanup }
  host_free(a_dev);
  host_free(b_dev);
  host_free(c_dev);
end;

{ --- Main --- }
begin
  try
    Writeln('Initializing CUDA shim...');
    cuda_init();
    Writeln('Allocating and launching test kernel...');
    test_vector_add(1024);
    Writeln('Finalizing...');
    cuda_finalize();
    check_no_leaks();
    Writeln('Done.');
  except
    on E: Exception do
      Writeln('Error: ', E.ClassName, ': ', E.Message);
  end;
end.