made it possible to send expression to gpu alongside the needed data
Some checks failed
CI / Julia ${{ matrix.version }} - ${{ matrix.os }} - ${{ matrix.arch }} - ${{ github.event_name }} (x64, ubuntu-latest, 1.10) (push) Has been cancelled
CI / Julia ${{ matrix.version }} - ${{ matrix.os }} - ${{ matrix.arch }} - ${{ github.event_name }} (x64, ubuntu-latest, 1.6) (push) Has been cancelled
CI / Julia ${{ matrix.version }} - ${{ matrix.os }} - ${{ matrix.arch }} - ${{ github.event_name }} (x64, ubuntu-latest, pre) (push) Has been cancelled
Some checks failed
CI / Julia ${{ matrix.version }} - ${{ matrix.os }} - ${{ matrix.arch }} - ${{ github.event_name }} (x64, ubuntu-latest, 1.10) (push) Has been cancelled
CI / Julia ${{ matrix.version }} - ${{ matrix.os }} - ${{ matrix.arch }} - ${{ github.event_name }} (x64, ubuntu-latest, 1.6) (push) Has been cancelled
CI / Julia ${{ matrix.version }} - ${{ matrix.os }} - ${{ matrix.arch }} - ${{ github.event_name }} (x64, ubuntu-latest, pre) (push) Has been cancelled
This commit is contained in:
parent
3145691d27
commit
e1097202ab
|
@ -1,6 +1,6 @@
|
||||||
module ExpressionExecutorCuda
|
module ExpressionExecutorCuda
|
||||||
include("Interpreter.jl")
|
|
||||||
include("ExpressionProcessing.jl")
|
include("ExpressionProcessing.jl")
|
||||||
|
include("Interpreter.jl")
|
||||||
|
|
||||||
export interpret_gpu
|
export interpret_gpu
|
||||||
export evaluate_gpu
|
export evaluate_gpu
|
||||||
|
@ -33,28 +33,6 @@ end
|
||||||
function evaluate_gpu(exprs::Vector{Expr}, X::Matrix{Float32}, p::Vector{Vector{Float32}})::Matrix{Float32}
|
function evaluate_gpu(exprs::Vector{Expr}, X::Matrix{Float32}, p::Vector{Vector{Float32}})::Matrix{Float32}
|
||||||
end
|
end
|
||||||
|
|
||||||
function test()
|
|
||||||
Interpreter.CudaTest()
|
|
||||||
end
|
|
||||||
|
|
||||||
"Performs pre processing steps to the expressions.
|
|
||||||
- It replaces every variable with the according value stored in X and p.
|
|
||||||
- It transforms the expressions into postfix form and returns them.
|
|
||||||
"
|
|
||||||
function preprocess_expressions!(exprs::Vector{Expr}, X::Matrix{Float64}, p::Vector{Vector{Float64}})::Array{String}
|
|
||||||
symtable = ExpressionProcessing.construct_symtable(exprs, X, p)
|
|
||||||
postfixExpressions = Array{String,1}()
|
|
||||||
|
|
||||||
# Test if multi threading provides a speedup and if it does, roughly determin the size at which it is beneficial.
|
|
||||||
for i in eachindex(exprs)
|
|
||||||
expr = deepcopy(exprs[i])
|
|
||||||
ExpressionProcessing.replace_variables!(exprs[i], symtable, expr)
|
|
||||||
push!(postfixExpressions, ExpressionProcessing.expr_to_postfix(exprs[i]))
|
|
||||||
end
|
|
||||||
|
|
||||||
return postfixExpressions
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,17 +1,22 @@
|
||||||
module ExpressionProcessing
|
module ExpressionProcessing
|
||||||
|
|
||||||
export construct_symtable
|
|
||||||
export replace_variables!
|
|
||||||
export expr_to_postfix
|
export expr_to_postfix
|
||||||
export SymbolTable64
|
|
||||||
export PostfixType
|
export PostfixType
|
||||||
export Operator, Add, Subtract, Multiply, Divide, Power, Abs, Log, Exp, Sqrt
|
export Operator, Add, Subtract, Multiply, Divide, Power, Abs, Log, Exp, Sqrt
|
||||||
|
export ElementType, FLOAT64, OPERATOR, INT64
|
||||||
|
export ExpressionElement
|
||||||
|
|
||||||
@enum Operator Add=1 Subtract=2 Multiply=3 Divide=4 Power=5 Abs=6 Log=7 Exp=8 Sqrt=9
|
@enum Operator::Int64 Add=1 Subtract=2 Multiply=3 Divide=4 Power=5 Abs=6 Log=7 Exp=8 Sqrt=9
|
||||||
const SymbolTable64 = Dict{Tuple{Expr, Symbol},Float64}
|
@enum ElementType FLOAT64=1 OPERATOR=2 INT64=3
|
||||||
const PostfixType = Vector{Union{Float64,Operator,Symbol}}
|
|
||||||
|
|
||||||
# Maybe switch from Array{String} to Array{Union{Float64, Symbol}}?
|
struct ExpressionElement
|
||||||
|
Type::ElementType
|
||||||
|
value::Int64 # Reinterpret the stored value to type "ElementType" when using it
|
||||||
|
end
|
||||||
|
|
||||||
|
const PostfixType = Vector{ExpressionElement}
|
||||||
|
|
||||||
|
"Converts a julia expression to its postfix notation"
|
||||||
function expr_to_postfix(expr::Expr)::PostfixType
|
function expr_to_postfix(expr::Expr)::PostfixType
|
||||||
postfix = PostfixType()
|
postfix = PostfixType()
|
||||||
operator = get_operator(expr.args[1])
|
operator = get_operator(expr.args[1])
|
||||||
|
@ -20,20 +25,81 @@ function expr_to_postfix(expr::Expr)::PostfixType
|
||||||
for j in 2:length(expr.args)
|
for j in 2:length(expr.args)
|
||||||
arg = expr.args[j]
|
arg = expr.args[j]
|
||||||
if typeof(arg) === Expr
|
if typeof(arg) === Expr
|
||||||
|
# exprElement = convert_to_ExpressionElement()
|
||||||
append!(postfix, expr_to_postfix(arg))
|
append!(postfix, expr_to_postfix(arg))
|
||||||
elseif typeof(arg) === Symbol # variables/parameters
|
elseif typeof(arg) === Symbol # variables/parameters
|
||||||
push!(postfix, arg)
|
exprElement = convert_to_ExpressionElement(convert_var_to_int(arg))
|
||||||
|
push!(postfix, exprElement)
|
||||||
else
|
else
|
||||||
push!(postfix, convert(Float64, arg))
|
exprElement = convert_to_ExpressionElement(convert(Float64, arg))
|
||||||
|
push!(postfix, exprElement)
|
||||||
end
|
end
|
||||||
if length(postfix) >= 2
|
if length(postfix) >= 2
|
||||||
push!(postfix, operator)
|
exprElement = convert_to_ExpressionElement(operator)
|
||||||
|
push!(postfix, exprElement)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
return postfix
|
return postfix
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function get_operator(op::Symbol)::Operator
|
||||||
|
if op == :+
|
||||||
|
return Add
|
||||||
|
elseif op == :-
|
||||||
|
return Subtract
|
||||||
|
elseif op == :*
|
||||||
|
return Multiply
|
||||||
|
elseif op == :/
|
||||||
|
return Divide
|
||||||
|
elseif op == :^
|
||||||
|
return Power
|
||||||
|
elseif op == :abs
|
||||||
|
return Abs
|
||||||
|
elseif op == :log
|
||||||
|
return Log
|
||||||
|
elseif op == :exp
|
||||||
|
return Exp
|
||||||
|
elseif op == :sqrt
|
||||||
|
return Sqrt
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
"Extracts the number from a variable/parameter and returns it. If the symbol is a parameter ```pn```, the resulting value will be negativ.
|
||||||
|
|
||||||
|
```x0 and p0``` are not allowed."
|
||||||
|
function convert_var_to_int(var::Symbol)::Int
|
||||||
|
varStr = String(var)
|
||||||
|
number = parse(Int32, SubString(varStr, 2))
|
||||||
|
|
||||||
|
if varStr[1] == 'p'
|
||||||
|
number = -number
|
||||||
|
end
|
||||||
|
|
||||||
|
return number
|
||||||
|
end
|
||||||
|
|
||||||
|
function convert_to_ExpressionElement(element)::ExpressionElement
|
||||||
|
value = reinterpret(Int64, element)
|
||||||
|
if element isa Float64
|
||||||
|
return ExpressionElement(FLOAT64, value)
|
||||||
|
elseif element isa Int64
|
||||||
|
return ExpressionElement(INT64, value)
|
||||||
|
elseif element isa Operator
|
||||||
|
return ExpressionElement(OPERATOR, value)
|
||||||
|
else
|
||||||
|
error("Element was of type '$(typeof(element))', which is not supported.")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#
|
||||||
|
# Everything below is currently not needed. Left here for potential future use
|
||||||
|
#
|
||||||
|
|
||||||
|
const SymbolTable64 = Dict{Tuple{Expr, Symbol},Float64}
|
||||||
|
|
||||||
"Replaces all the variables and parameters of the given expression with their corresponding value stored in the symtable
|
"Replaces all the variables and parameters of the given expression with their corresponding value stored in the symtable
|
||||||
# Arguments
|
# Arguments
|
||||||
- `symtable::SymbolTable64`: Contains the values of all variables for each expression
|
- `symtable::SymbolTable64`: Contains the values of all variables for each expression
|
||||||
|
@ -78,26 +144,4 @@ function fill_symtable!(expr::Expr, symtable::SymbolTable64, values::Vector{Floa
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function get_operator(op::Symbol)::Operator
|
|
||||||
if op == :+
|
|
||||||
return Add
|
|
||||||
elseif op == :-
|
|
||||||
return Subtract
|
|
||||||
elseif op == :*
|
|
||||||
return Multiply
|
|
||||||
elseif op == :/
|
|
||||||
return Divide
|
|
||||||
elseif op == :^
|
|
||||||
return Power
|
|
||||||
elseif op == :abs
|
|
||||||
return Abs
|
|
||||||
elseif op == :log
|
|
||||||
return Log
|
|
||||||
elseif op == :exp
|
|
||||||
return Exp
|
|
||||||
elseif op == :sqrt
|
|
||||||
return Sqrt
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
end
|
|
@ -1,36 +1,8 @@
|
||||||
module Interpreter
|
module Interpreter
|
||||||
using CUDA
|
using CUDA
|
||||||
include("ExpressionProcessing.jl")
|
using ..ExpressionProcessing
|
||||||
using .ExpressionProcessing: PostfixType, Add, Subtract, Operator
|
|
||||||
|
|
||||||
export Interpret
|
export interpret
|
||||||
export CudaTest
|
|
||||||
|
|
||||||
function CudaTest()
|
|
||||||
N = 2^20
|
|
||||||
x = CUDA.fill(1.0f0, N)
|
|
||||||
y = CUDA.fill(2.0f0, N)
|
|
||||||
|
|
||||||
kernelAdd = @cuda launch=false InterpretExplicit!(ExpressionProcessing.Add, x, y)
|
|
||||||
# kernelAdd = @cuda launch=false InterpretExplicit!(Add, x, y, reference)
|
|
||||||
config = launch_configuration(kernelAdd.fun)
|
|
||||||
threads = min(length(y), config.threads)
|
|
||||||
blocks = cld(length(y), threads)
|
|
||||||
|
|
||||||
kernelAdd(Add, x, y; threads, blocks)
|
|
||||||
# println(y[1])
|
|
||||||
# @test all(Array(y) .== 3.0f0)
|
|
||||||
|
|
||||||
kernelSubtract = @cuda launch=false InterpretExplicit!(ExpressionProcessing.Subtract, x, y)
|
|
||||||
configSub = launch_configuration(kernelSubtract.fun)
|
|
||||||
threadsSub = min(length(y), configSub.threads)
|
|
||||||
blocksSub = cld(length(y), threadsSub)
|
|
||||||
CUDA.fill!(y, 2.0f0)
|
|
||||||
|
|
||||||
# kernelSubtract(Subtract, x, y; threadsSub, blocksSub)
|
|
||||||
# @test all(Array(y) .== -1.0f0)
|
|
||||||
# println(y[1])
|
|
||||||
end
|
|
||||||
|
|
||||||
"Interprets the given expressions with the values provided.
|
"Interprets the given expressions with the values provided.
|
||||||
# Arguments
|
# Arguments
|
||||||
|
@ -38,19 +10,49 @@ end
|
||||||
- variables::Matrix{Float64} : The variables to use. Each column is mapped to the variables x1..xn
|
- variables::Matrix{Float64} : The variables to use. Each column is mapped to the variables x1..xn
|
||||||
- parameters::Vector{Vector{Float64}} : The parameters to use. Each Vector contains the values for the parameters p1..pn. The number of parameters can be different for every expression
|
- parameters::Vector{Vector{Float64}} : The parameters to use. Each Vector contains the values for the parameters p1..pn. The number of parameters can be different for every expression
|
||||||
"
|
"
|
||||||
function Interpret(expressions::Vector{ExpressionProcessing.PostfixType}, variables::Matrix{Float64}, parameters::Vector{Vector{Float64}})
|
function interpret(expressions::Vector{ExpressionProcessing.PostfixType}, variables::Matrix{Float64}, parameters::Vector{Vector{Float64}})
|
||||||
# TODO:
|
# TODO:
|
||||||
# create CUDA array and fill it with the expressions, variables and parameters
|
# create CUDA array and fill it with the variables and parameters
|
||||||
# calculate needed number of threads, probably based off of the number of expressions, so I can ensure each warp takes the same execution path
|
# create CUDA array for calculation results
|
||||||
# Start the kernel
|
variableRows = size(variables, 1)
|
||||||
cudaExprs = Vector{CuArray{ExpressionProcessing.PostfixType}}(undef, length(expressions))
|
cudaVars = CuArray(variables)
|
||||||
|
|
||||||
|
paramRows = get_max_parameter_rows(parameters)
|
||||||
|
p1aramCols = length(parameters)
|
||||||
|
cudaParams = CuArray{Float64}(undef, p1aramCols, paramRows) # length(parameters) == number of expressions
|
||||||
|
# TODO: Fill cudaParams
|
||||||
|
|
||||||
|
# TODO: Move CuArray(expression[i]) outside the loop for a more efficient transfer to GPU but leave kernel signature as is
|
||||||
for i in eachindex(expressions)
|
for i in eachindex(expressions)
|
||||||
push!(cudaExprs, CuArray(expressions[i]))
|
cudaExpr = CuArray(expressions[i])
|
||||||
|
kernel = @cuda launch=false interpret_expression(cudaExpr, cudaVars, cudaParams, i)
|
||||||
|
config = launch_configuration(kernel.fun)
|
||||||
|
threads = min(variableRows, config.threads)
|
||||||
|
blocks = cld(variableRows, threads)
|
||||||
|
|
||||||
|
kernel(cudaExpr, cudaVars, cudaParams, i; threads, blocks)
|
||||||
end
|
end
|
||||||
# cudaExprs = CuArray(copy(expressions))
|
end
|
||||||
|
|
||||||
|
function interpret_expression(expression, variables, parameters, exprIndex::Int)
|
||||||
|
#TODO Implement interpreter
|
||||||
|
end
|
||||||
|
|
||||||
|
"Retrieves the number of entries for the largest inner vector"
|
||||||
|
function get_max_parameter_rows(params::Vector{Vector{T}})::Int where T
|
||||||
|
maxLength = 0
|
||||||
|
for i in eachindex(params)
|
||||||
|
if length(params) > maxLength
|
||||||
|
maxLength = length(params)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return maxLength
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@deprecate InterpretExplicit!(op::Operator, x, y) interpret_expression(expression, variables, parameters, exprIndex::Int)
|
||||||
# Kernel
|
# Kernel
|
||||||
function InterpretExplicit!(op::Operator, x, y)
|
function InterpretExplicit!(op::Operator, x, y)
|
||||||
index = (blockIdx().x - 1) * blockDim().x + threadIdx().x
|
index = (blockIdx().x - 1) * blockDim().x + threadIdx().x
|
||||||
|
|
|
@ -11,28 +11,21 @@ variables[1,2] = 3
|
||||||
parameters[1] = Vector{Float64}(undef, 1)
|
parameters[1] = Vector{Float64}(undef, 1)
|
||||||
parameters[1][1] = 5
|
parameters[1][1] = 5
|
||||||
|
|
||||||
@testset "Test symtable construction" begin
|
@testset "Test conversion expression element" begin
|
||||||
symtable = construct_symtable(expressions, variables, parameters)
|
reference1 = ExpressionElement(FLOAT64, reinterpret(Int64, 1.0))
|
||||||
@test haskey(symtable, (expressions[1], :x1))
|
reference2 = ExpressionElement(INT64, reinterpret(Int64, 1))
|
||||||
@test haskey(symtable, (expressions[1], :x2))
|
reference3 = ExpressionElement(OPERATOR, reinterpret(Int64, Add))
|
||||||
@test haskey(symtable, (expressions[1], :p1))
|
|
||||||
|
|
||||||
@test symtable[(expressions[1], :x1)] ≈ 2.0 atol=0.01
|
@test isequal(reference1, ExpressionProcessing.convert_to_ExpressionElement(1.0))
|
||||||
@test symtable[(expressions[1], :x2)] ≈ 3.0 atol=0.01
|
@test isequal(reference2, ExpressionProcessing.convert_to_ExpressionElement(1))
|
||||||
@test symtable[(expressions[1], :p1)] ≈ 5.0 atol=0.01
|
@test isequal(reference3, ExpressionProcessing.convert_to_ExpressionElement(Add))
|
||||||
end
|
|
||||||
|
|
||||||
@testset "Test variable replacement in expression" begin
|
|
||||||
symtable = construct_symtable(expressions, variables, parameters)
|
|
||||||
exprCopy = deepcopy(expressions[1])
|
|
||||||
replace_variables!(exprCopy, symtable, expressions[1])
|
|
||||||
|
|
||||||
@test eval(exprCopy) == 10 # If it can be evaluated, it means all variables have been replaced, as there are no globally defined variables
|
|
||||||
end
|
end
|
||||||
|
|
||||||
@testset "Test conversion to postfix" begin
|
@testset "Test conversion to postfix" begin
|
||||||
reference = PostfixType()
|
reference = PostfixType()
|
||||||
append!(reference, [:x1, 1.0, :x2, Multiply, Add, :p1, Add])
|
|
||||||
|
append!(reference, [ExpressionProcessing.convert_to_ExpressionElement(1), ExpressionProcessing.convert_to_ExpressionElement(1.0), ExpressionProcessing.convert_to_ExpressionElement(2), ExpressionProcessing.convert_to_ExpressionElement(Multiply),
|
||||||
|
ExpressionProcessing.convert_to_ExpressionElement(Add), ExpressionProcessing.convert_to_ExpressionElement(-1), ExpressionProcessing.convert_to_ExpressionElement(Add)])
|
||||||
postfix = expr_to_postfix(expressions[1])
|
postfix = expr_to_postfix(expressions[1])
|
||||||
|
|
||||||
@test isequal(reference, postfix)
|
@test isequal(reference, postfix)
|
||||||
|
|
Loading…
Reference in New Issue
Block a user