Current section
Files
Jump to
Current section
Files
src/focused_test.erl
-module(focused_test).
-export([test_actual_capabilities/0]).
test_actual_capabilities() ->
io:format("=== Testing Actual MLX Capabilities ===~n~n"),
% Add the MLX library to the code path
code:add_path("mlx/_build/default/lib/mlx/ebin"),
Tests = [
{"Core NIF Functionality", fun test_core_nif/0},
{"Array Creation & Operations", fun test_array_ops/0},
{"Matrix Operations", fun test_matrix_ops/0},
{"Device Management", fun test_device_mgmt/0},
{"Performance Testing", fun test_performance_scaling/0},
{"Error Handling", fun test_error_handling/0},
{"Memory Management", fun test_memory_mgmt/0},
{"Advanced Array Features", fun test_advanced_arrays/0}
],
Results = lists:map(fun({TestName, TestFun}) ->
io:format("~n--- Testing ~s ---~n", [TestName]),
try
TestFun(),
io:format("✓ ~s: PASS~n", [TestName]),
{TestName, pass}
catch
Class:Reason:Stack ->
io:format("✗ ~s: FAIL - ~p:~p~n", [TestName, Class, Reason]),
io:format(" Stack: ~p~n", [Stack]),
{TestName, {fail, {Class, Reason}}}
end
end, Tests),
% Summary
PassedTests = length([Result || {_, pass} = Result <- Results]),
TotalTests = length(Results),
io:format("~n=== Final Results ===~n"),
io:format("Passed: ~p/~p test categories~n", [PassedTests, TotalTests]),
case PassedTests of
TotalTests ->
io:format("🎉 ALL ACTUAL CAPABILITIES WORKING!~n");
_ ->
io:format("⚠️ Some capabilities failed:~n"),
[io:format(" - ~s~n", [Name]) || {Name, Status} <- Results, Status =/= pass]
end,
Results.
test_core_nif() ->
io:format(" Testing core NIF loading and basic functions...~n"),
% Test NIF version
{ok, mlx_loaded} = mlx_nif:version(),
io:format(" ✓ NIF loaded successfully~n"),
% Test basic functionality
{ok, {test_passed, Shape, Dtype}} = mlx_nif:test_basic(),
io:format(" ✓ Basic test passed: Shape=~p, Dtype=~p~n", [Shape, Dtype]),
ok.
test_array_ops() ->
io:format(" Testing array creation and basic operations...~n"),
% Test different data types
DataTypes = [float32, int32],
lists:foreach(fun(DType) ->
{ok, A} = mlx_nif:zeros([3, 4], DType),
{ok, [3, 4]} = mlx_nif:shape(A),
io:format(" ✓ ~p arrays: creation and shape~n", [DType])
end, DataTypes),
% Test arithmetic operations
{ok, A} = mlx_nif:ones([3, 3], float32),
{ok, B} = mlx_nif:ones([3, 3], float32),
{ok, Sum} = mlx_nif:add(A, B),
{ok, Prod} = mlx_nif:multiply(A, B),
% Verify shapes
{ok, [3, 3]} = mlx_nif:shape(Sum),
{ok, [3, 3]} = mlx_nif:shape(Prod),
% Test evaluation
ok = mlx_nif:eval(Sum),
ok = mlx_nif:eval(Prod),
io:format(" ✓ Arithmetic operations: add, multiply~n"),
io:format(" ✓ Lazy evaluation working~n"),
ok.
test_matrix_ops() ->
io:format(" Testing matrix operations...~n"),
% Test various matrix multiplication sizes
TestSizes = [
{[2, 3], [3, 4], [2, 4]},
{[5, 7], [7, 3], [5, 3]},
{[10, 8], [8, 12], [10, 12]}
],
lists:foreach(fun({ShapeA, ShapeB, ExpectedShape}) ->
{ok, A} = mlx_nif:ones(ShapeA, float32),
{ok, B} = mlx_nif:ones(ShapeB, float32),
{ok, C} = mlx_nif:matmul(A, B),
{ok, ExpectedShape} = mlx_nif:shape(C),
ok = mlx_nif:eval(C),
io:format(" ✓ Matrix multiply: ~p × ~p = ~p~n", [ShapeA, ShapeB, ExpectedShape])
end, TestSizes),
ok.
test_device_mgmt() ->
io:format(" Testing device management...~n"),
% Test CPU device
ok = mlx_nif:set_default_device(cpu),
{ok, A_cpu} = mlx_nif:zeros([10, 10], float32),
ok = mlx_nif:eval(A_cpu),
io:format(" ✓ CPU device working~n"),
% Test GPU device (may not be available)
case mlx_nif:set_default_device(gpu) of
ok ->
{ok, A_gpu} = mlx_nif:ones([10, 10], float32),
ok = mlx_nif:eval(A_gpu),
io:format(" ✓ GPU device available and working~n"),
% Switch back to CPU
ok = mlx_nif:set_default_device(cpu);
{error, Reason} ->
io:format(" ✓ GPU device not available (~p) - CPU fallback working~n", [Reason])
end,
ok.
test_performance_scaling() ->
io:format(" Testing performance scaling...~n"),
% Test performance with increasing sizes
Sizes = [50, 100, 200, 500, 1000],
Results = lists:map(fun(Size) ->
StartTime = erlang:monotonic_time(microsecond),
{ok, A} = mlx_nif:ones([Size, Size], float32),
{ok, B} = mlx_nif:ones([Size, Size], float32),
{ok, C} = mlx_nif:matmul(A, B),
ok = mlx_nif:eval(C),
EndTime = erlang:monotonic_time(microsecond),
Duration = (EndTime - StartTime) / 1000, % Convert to milliseconds
io:format(" ✓ ~px~p matrix multiply: ~.2fms~n", [Size, Size, Duration]),
{Size, Duration}
end, Sizes),
% Check that performance scales reasonably
[Size1, Size2, Size3, Size4, Size5] = Sizes,
[{_, Time1}, {_, Time2}, {_, Time3}, {_, Time4}, {_, Time5}] = Results,
% Larger operations should generally take more time (with some variance)
io:format(" ✓ Performance scaling analysis:~n"),
io:format(" ~px~p: ~.2fms (baseline)~n", [Size1, Size1, Time1]),
io:format(" ~px~p: ~.2fms (~.1fx)~n", [Size5, Size5, Time5, Time5/Time1]),
ok.
test_error_handling() ->
io:format(" Testing error handling...~n"),
% Test invalid shapes
case mlx_nif:zeros([-1, 5], float32) of
{error, _} ->
io:format(" ✓ Invalid shape properly rejected~n");
_ ->
io:format(" ? Invalid shape not caught (may be valid in MLX)~n")
end,
% Test incompatible matrix multiplication
{ok, A} = mlx_nif:ones([3, 4], float32),
{ok, B} = mlx_nif:ones([5, 6], float32), % Incompatible with A
case mlx_nif:matmul(A, B) of
{error, _} ->
io:format(" ✓ Incompatible matmul properly rejected~n");
_ ->
io:format(" ? Incompatible matmul not caught (may be broadcasting)~n")
end,
% Test invalid device
case mlx_nif:set_default_device(invalid_device) of
{error, _} ->
io:format(" ✓ Invalid device properly rejected~n");
_ ->
io:format(" ? Invalid device not caught~n")
end,
ok.
test_memory_mgmt() ->
io:format(" Testing memory management...~n"),
% Create many arrays to test memory handling
NumArrays = 100,
Arrays = lists:map(fun(I) ->
{ok, A} = mlx_nif:zeros([10, 10], float32),
ok = mlx_nif:eval(A),
A
end, lists:seq(1, NumArrays)),
io:format(" ✓ Created ~p arrays without memory issues~n", [NumArrays]),
% Test large array
{ok, LargeArray} = mlx_nif:zeros([2000, 2000], float32),
ok = mlx_nif:eval(LargeArray),
io:format(" ✓ Large array (2000x2000) handled successfully~n"),
% Force garbage collection
erlang:garbage_collect(),
io:format(" ✓ Garbage collection completed~n"),
ok.
test_advanced_arrays() ->
io:format(" Testing advanced array features...~n"),
% Test different shapes and sizes
Shapes = [
[1], % 1D
[5, 5], % 2D square
[3, 7], % 2D rectangular
[2, 3, 4], % 3D
[2, 2, 2, 2] % 4D
],
lists:foreach(fun(Shape) ->
{ok, A} = mlx_nif:zeros(Shape, float32),
{ok, Shape} = mlx_nif:shape(A),
ok = mlx_nif:eval(A),
io:format(" ✓ Shape ~p: creation and evaluation~n", [Shape])
end, Shapes),
% Test chain of operations
{ok, A} = mlx_nif:ones([5, 5], float32),
{ok, B} = mlx_nif:ones([5, 5], float32),
{ok, C} = mlx_nif:add(A, B),
{ok, D} = mlx_nif:multiply(C, B),
{ok, E} = mlx_nif:add(D, A),
ok = mlx_nif:eval(E),
io:format(" ✓ Chained operations: A + B -> (result * B) + A~n"),
ok.