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
|
||||
include("Interpreter.jl")
|
||||
include("ExpressionProcessing.jl")
|
||||
include("Interpreter.jl")
|
||||
|
||||
export interpret_gpu
|
||||
export evaluate_gpu
|
||||
|
@ -33,28 +33,6 @@ end
|
|||
function evaluate_gpu(exprs::Vector{Expr}, X::Matrix{Float32}, p::Vector{Vector{Float32}})::Matrix{Float32}
|
||||
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
|
||||
|
||||
|
||||
|
|
|
@ -1,17 +1,22 @@
|
|||
module ExpressionProcessing
|
||||
|
||||
export construct_symtable
|
||||
export replace_variables!
|
||||
export expr_to_postfix
|
||||
export SymbolTable64
|
||||
export PostfixType
|
||||
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
|
||||
const SymbolTable64 = Dict{Tuple{Expr, Symbol},Float64}
|
||||
const PostfixType = Vector{Union{Float64,Operator,Symbol}}
|
||||
@enum Operator::Int64 Add=1 Subtract=2 Multiply=3 Divide=4 Power=5 Abs=6 Log=7 Exp=8 Sqrt=9
|
||||
@enum ElementType FLOAT64=1 OPERATOR=2 INT64=3
|
||||
|
||||
# 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
|
||||
postfix = PostfixType()
|
||||
operator = get_operator(expr.args[1])
|
||||
|
@ -20,20 +25,81 @@ function expr_to_postfix(expr::Expr)::PostfixType
|
|||
for j in 2:length(expr.args)
|
||||
arg = expr.args[j]
|
||||
if typeof(arg) === Expr
|
||||
# exprElement = convert_to_ExpressionElement()
|
||||
append!(postfix, expr_to_postfix(arg))
|
||||
elseif typeof(arg) === Symbol # variables/parameters
|
||||
push!(postfix, arg)
|
||||
exprElement = convert_to_ExpressionElement(convert_var_to_int(arg))
|
||||
push!(postfix, exprElement)
|
||||
else
|
||||
push!(postfix, convert(Float64, arg))
|
||||
exprElement = convert_to_ExpressionElement(convert(Float64, arg))
|
||||
push!(postfix, exprElement)
|
||||
end
|
||||
if length(postfix) >= 2
|
||||
push!(postfix, operator)
|
||||
exprElement = convert_to_ExpressionElement(operator)
|
||||
push!(postfix, exprElement)
|
||||
end
|
||||
end
|
||||
|
||||
return postfix
|
||||
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
|
||||
# Arguments
|
||||
- `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
|
||||
|
||||
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
|
|
@ -1,36 +1,8 @@
|
|||
module Interpreter
|
||||
using CUDA
|
||||
include("ExpressionProcessing.jl")
|
||||
using .ExpressionProcessing: PostfixType, Add, Subtract, Operator
|
||||
using ..ExpressionProcessing
|
||||
|
||||
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
|
||||
export interpret
|
||||
|
||||
"Interprets the given expressions with the values provided.
|
||||
# Arguments
|
||||
|
@ -38,19 +10,49 @@ end
|
|||
- 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
|
||||
"
|
||||
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:
|
||||
# create CUDA array and fill it with the expressions, 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
|
||||
# Start the kernel
|
||||
cudaExprs = Vector{CuArray{ExpressionProcessing.PostfixType}}(undef, length(expressions))
|
||||
# create CUDA array and fill it with the variables and parameters
|
||||
# create CUDA array for calculation results
|
||||
variableRows = size(variables, 1)
|
||||
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)
|
||||
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
|
||||
# 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
|
||||
|
||||
|
||||
|
||||
@deprecate InterpretExplicit!(op::Operator, x, y) interpret_expression(expression, variables, parameters, exprIndex::Int)
|
||||
# Kernel
|
||||
function InterpretExplicit!(op::Operator, x, y)
|
||||
index = (blockIdx().x - 1) * blockDim().x + threadIdx().x
|
||||
|
|
|
@ -11,28 +11,21 @@ variables[1,2] = 3
|
|||
parameters[1] = Vector{Float64}(undef, 1)
|
||||
parameters[1][1] = 5
|
||||
|
||||
@testset "Test symtable construction" begin
|
||||
symtable = construct_symtable(expressions, variables, parameters)
|
||||
@test haskey(symtable, (expressions[1], :x1))
|
||||
@test haskey(symtable, (expressions[1], :x2))
|
||||
@test haskey(symtable, (expressions[1], :p1))
|
||||
@testset "Test conversion expression element" begin
|
||||
reference1 = ExpressionElement(FLOAT64, reinterpret(Int64, 1.0))
|
||||
reference2 = ExpressionElement(INT64, reinterpret(Int64, 1))
|
||||
reference3 = ExpressionElement(OPERATOR, reinterpret(Int64, Add))
|
||||
|
||||
@test symtable[(expressions[1], :x1)] ≈ 2.0 atol=0.01
|
||||
@test symtable[(expressions[1], :x2)] ≈ 3.0 atol=0.01
|
||||
@test symtable[(expressions[1], :p1)] ≈ 5.0 atol=0.01
|
||||
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
|
||||
@test isequal(reference1, ExpressionProcessing.convert_to_ExpressionElement(1.0))
|
||||
@test isequal(reference2, ExpressionProcessing.convert_to_ExpressionElement(1))
|
||||
@test isequal(reference3, ExpressionProcessing.convert_to_ExpressionElement(Add))
|
||||
end
|
||||
|
||||
@testset "Test conversion to postfix" begin
|
||||
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])
|
||||
|
||||
@test isequal(reference, postfix)
|
||||
|
|
Loading…
Reference in New Issue
Block a user