NAME
SPVM::Document::Tutorial - SPVM Performance Tutorial
DESCRIPTION
SPVM Tutorial
TUTORIAL
SPVM Installation
SPMV Installation is described. SPVM is a programing language, but also SPVM is a CPAN module writen by Perl and C language. You can install SPVM from CPAN using cpan or cpanm command.
Install SPVM using
cpanm if you has user Perl in user directory using
perlbrew or
plenv.
cpanm SPVM
Install SPVM using cpan command.
cpan SPVM
What are the Advantages that SPVM programming language is a CPAN module?
The Advantages is that you can upgrade by simply installing SPVM from CPAN.
SPVM is a programming language, but also a Perl module, and works with Perl.
Binary compatibility is kept in upgrading unlike Perl in this point.
SPVM has a Native API for operating SPVM in cooperation with C language. In the C language level, SPVM has a way to keep the backward compatibility when upgrading.
SPVM Getting Started
Let's take SPVM for the first time. Then, let's improve the performance of the SPVM code.
First SPVM Program
Let's take SPVM for the first time. This is a first simple example. Let's calcurate the sum of numbers.
Create SPVM module
Create SPVM module. The extension is "spvm". In this example, the name of SPVM module is "SPVM/MyMath.spvm".
Create "SPVM/MyMath.spvm" in the "lib" directory, and you write the following code.
# lib/SPVM/MyMath.spvm
class MyMath {
static method sum : int ($nums : int[]) {
my $total = 0;
for (my $i = 0; $i < @$nums; $i++) {
$total += $nums->[$i];
}
return $total;
}
}
Class Definition
Write
Class Definition by
class keyword. Unlike Perl, SPVM always need class. The whole SPVM grammar is a set of classes.
# Class Definition
class MyMath {
}
See also
Class - SPVM Language Specification about Class.
Method Definition
Write
Method Definition by
sub keyword. Unlike Perl, SPVM Method Definition have return type and argument types.
class MyMath {
# Method Definition
static method sum : int ($nums : int[]) {
}
}
See also
Method - SPVM Language Specification about Method.
Numeric Types
int type in sum return value is signed 32bit integer type. This is same as C99 int32_t.
int
SPVM has the following types as other numeric types.
SPVM numric type
|
C99 type
|
byte
|
int8_t
|
short
|
int16_t
|
int
|
int32_t
|
long
|
int64_t
|
float
|
float
|
double
|
double
|
See also
Type - SPVM Language Specification about Type.
Array Types
int[] type in sum arguments is array of int type.
int[]
The numeric array type guarantees that the values are consecutive in memory.
In this point, unlike Perl where all value are assigned to the dynamic type SV, SPVM has a static type, so it can represent a efficient sequence of numbers.
See also
Type - SPVM Language Specification about Type.
Local Variable Declaration
Write
Local Variable Declaration by
my keyword. You can initialize variables at the same time you declare variables.
my $total = 0;
The above declaration has the same meaning as:
my $total : int = 0;
0 on the right side is a signed 32-bit integer, so the type of the variable is automatically determined by type inference.
See also
Lexical Variabe - SPVM Language Specification about Lexical Variabe Declaration.
See also
Type Inference - SPVM Language Specification about Type Inference.
Integer Literal
0 is Integer Literal.
my $total : int = 0;
SPVM has the following Literal.
- Integer Literal
- Floating Point Literal
- Charater Literal
- String Literal
# Integer Literal
123
123_456_789
# Floating Point Literal
1.32
1.32f
# Character Literal
'a'
'c'
# String Literal
"Hello World!"
See also
Literal - SPVM Language Specification about Literal.
Get Array Length
Let's look at the part where the sum of the arrays is calculated.
for (my $i = 0; $i < @$nums; $i++) {
$total += $nums->[$i];
}
See @$nums.
@$nums
@ is Array Length Operator to get array length.
Unlike Perl, which is context sensitive, Array Length Operator of SPVM always returns the length of the array.
Note that SPVM has no context.
See
Array Length Operator - SPVM Language Specification about Array Length Operator
Increment Operator
Incremental Operator increment the value.
$i++
See
Increment Operator - SPVM Language Specification about Incremental Operator.
See
Decrement Operator - SPVM Language Specification about Decrement Operator.
Array Access
Array Access can be done by "->" Arrow Operator.
$nums->[$i]
See
Array - SPVM Language Specification about Array operation.
Addition Operator
See the following code.
$total += $nums->[$i];
This is same as the following Additon Operator and Assignment Operator.
$total = $total + $nums->[$i];
SPVM has many operators.
See
Operator - SPVM Language Specification about Opeartor.
for Statement
Next, see for Statement.
for (my $i = 0; $i < @$nums; $i++) {
$total += $nums->[$i];
}
See
for Statement - SPVM Language Specification about for Statement.
See
Statement - SPVM Language Specification about Statement like if Statement, while Statement, and switch Statement.
return Statement
At last, return Statement.
return $total;
See
return Statement - SPVM Language Specification about return Statement.
Call SPVM Method from Perl
Create "sum.pl" file and write the following code. This is Perl program.
use strict;
use warnings;
use FindBin;
use lib "$FindBin::Bin/lib";
use SPVM 'MyMath';
# Call method
my $total = SPVM::MyMath->sum([3, 6, 8, 9]);
print "Total: $total\n";
# Call method with packed data
my $nums_packed = pack('l*', 3, 6, 8, 9);
my $sv_nums = SPVM::new_int_array_from_bin($nums_packed);
my $total_packed = SPVM::MyMath->sum($sv_nums);
print "Total Packed: $total_packed\n";
Add library path
The followings are the conventions and add current script directry's "lib" directory to library path .
use strict;
use warnings;
use FindBin;
use lib "$FindBin::Bin/lib";
use SPVM module
use SPVM module.
use SPVM 'MyMath';
In this place, compilation is not done. Collect SPVM modules.
Call SPVM Method
Call SPVM Method. It's amazing that SPVM method can be called as Perl method.
# Call method
my $total = SPVM::MyMath->sum([3, 6, 8, 9]);
Perl array reference is converted to SPVM int array.
See
Convert Perl Data to SPVM Value - SPVM Exchange API about Conversion of Perl Data to SPVM Value.
SPVM int return value is converted to Perl Scalar.
See
Converting SPVM Value to Perl Data - SPVM Exchange API about Conversion of Perl Data to SPVM Value.
Call SPVM Method with packed data
you can pass packed binary data. SPVM::new_int_array_from_bin create SPVM int array from packed binary data. This is efficient.
# Call method with packed data
my $nums_packed = pack('l*', 3, 6, 8, 9);
my $sv_nums = SPVM::new_int_array_from_bin($nums_packed);
my $total_packed = SPVM::MyMath->sum($sv_nums);
See
SPVM Exchange API about SPVM Exchange API like SPVM::new_int_array_from_bin.
How to improve SPVM Performance
See How to improve SPVM Performance.
If you're searching SPVM for performance reasons, here's what you really want to see.
How to improve SPVM Performance using SPVM Precompile and SPVM Native API
SPVM Module:
# lib/SPVM/MyMath.spvm
class MyMath {
static method sum : int ($nums : int[]) {
my $total = 0;
for (my $i = 0; $i < @$nums; $i++) {
$total += $nums->[$i];
}
return $total;
}
}
Use SPVM Module from Perl
# spvm.pl
use strict;
use warnings;
use FindBin;
use lib "$FindBin::Bin/lib";
use SPVM 'MyMath';
# Call method
my $total = SPVM::MyMath->sum([3, 6, 8, 9]);
print "Total: $total\n";
# Call method with packed data
my $nums_packed = pack('l*', 3, 6, 8, 9);
my $sv_nums = SPVM::new_int_array_from_bin($nums_packed);
my $total_packed = SPVM::MyMath->sum($sv_nums);
print "Total Packed: $total_packed\n";
Precompiled SPVM Method. This means SPVM code is converted to Machine Code:
# lib/SPVM/MyMath.spvm
class MyMath : precompile {
static method sum_precompile : int ($nums : int[]) {
my $total = 0;
for (my $i = 0; $i < @$nums; $i++) {
$total += $nums->[$i];
}
return $total;
}
}
Call SPVM Precompile Method from Perl
# spvm.pl
use strict;
use warnings;
use FindBin;
use lib "$FindBin::Bin/lib";
use SPVM 'MyMath';
# Call precompile method
my $total_precompile = SPVM::MyMath->sum_precompile([3, 6, 8, 9]);
print "Total Precompile: $total_precompile\n";
SPVM Native Method. This means SPVM method call C/C++ native method:
# lib/SPVM/MyMath.spvm
class MyMath {
native static method sum_native : int ($nums : int[]);
}
// lib/SPVM/MyMath.c
#include "spvm_native.h"
int32_t SPVM__SPVM__MyMath__sum_native(SPVM_ENV* env, SPVM_VALUE* stack) {
void* sv_nums = stack[0].oval;
int32_t length = env->length(env, sv_nums);
int32_t* nums = env->get_elems_int(env, sv_nums);
int32_t total = 0;
for (int32_t i = 0; i < length; i++) {
total += nums[i];
}
stack[0].ival = total;
return 0;
}
# lib/SPVM/MyMath.config
use strict;
use warnings;
use SPVM::Builder::Config;
my $bconf = SPVM::Builder::Config->new_c99;
$bconf;
Use SPVM Native Method from Perl
# spvm.pl
use strict;
use warnings;
use FindBin;
use lib "$FindBin::Bin/lib";
use SPVM 'MyMath';
# Call native method
my $total_native = SPVM::MyMath->sum_native([3, 6, 8, 9]);
print "Total Native: $total_native\n";
Environment Variable "SPVM_BUILD_DIR" must be set for precompile and native method
# bash example
export SPVM_BUILD_DIR=~/.spvm_build
How to Bind C/C++/CUDA Library to SPVM
The advantage of SPVM is that you can easily bind C/C++/CUDA.
Methods bound with SPVM can be easily called from Perl.
Before reading this page, you need to understand Native API.
Binding your own C language library
First, let's bind our own C library.
The following source code is the completed source code.
I will explain using this source code.
SPVM Native Example - Bind C Library
Create a C language library for summation and call it from Perl.
# bind_clib.pl
use strict;
use warnings;
use FindBin;
use lib "$FindBin::Bin/lib";
use SPVM 'BindCLib';
my $total = SPVM::BindCLib->sum([1, 2, 3, 4]);
print "Total: $total\n";
SPVM Method Definition.
# lib/SPVM/BindCLib.spvm
class BindCLib {
native static method sum : int ($nums : int[]);
}
Native Config.
# lib/SPVM/BindCLib.config
use strict;
use warnings;
use SPVM::Builder::Config;
my $bconf = SPVM::Builder::Config->new_c99;
$bconf;
Call C library from C program.
// lib/SPVM/BindCLib.c
#include "spvm_native.h"
#include "bind_clib.h"
int32_t SPVM__SPVM__BindCLib__sum(SPVM_ENV* env, SPVM_VALUE* stack) {
void* sv_nums = stack[0].oval;
int32_t length = env->length(env, sv_nums);
int32_t* nums = env->get_elems_int(env, sv_nums);
int32_t total = bind_clib_sum(nums, length);
stack[0].ival = total;
return 0;
}
Notice the line reading the header.
#include "bind_clib.h"
This header is included from "lib/SPVM/BindCLib.native/include/bind_clib.h". This is pure C header file.
#include
int32_t bind_clib_sum(int32_t* nums, int32_t length);
SPVM sets the include directory("SPVM/BindCLib.native/include") as the default header file read path.
C library source file is "lib/SPVM/BindCLib.native/src/bind_clib.c". This is pure C source file.
#include "bind_clib.h"
int32_t bind_clib_sum(int32_t* nums, int32_t length) {
int32_t total = 0;
for (int32_t i = 0; i < length; i++) {
total += nums[i];
}
return total;
}
SPVM compiles all source files in the source directory("SPVM/BindCLib.native/src"). It can contain multiple source files.
How to bind other C Library to SPVM
If you want to know more about the bindings of other C libraries, see the example below.
How to bind C++ Library to SPVM
If you want to know more about the bindings of C++ libraries to SPVM, see the example below.
How to bind CUDA to SPVM
If you want to know more about the bindings of CUDA to SPVM, see the example below.
Complex Tutorial
SPVM provides common arithmetic for complex numbers at the same level as C99.
Complex Type
Complex Type is Complex_2f for complex float and Complex_2d for complex double.
Complex_2f and Complex_2d is Multi Numeric Type. This is allocated on Method Call Stack.
This is not Object Type which is allocated on Heap Memory.
See SPVM Complex Examples at first.
Complex_2f
# Complex float type
use Complex_2f;
my $z : Complex_2f;
$z->{re} = 1.5f;
$z->{im} = 1.7f;
Complex_2d
# Complex double type
use Complex_2d;
my $z : Complex_2d;
$z->{re} = 1.5;
$z->{im} = 1.7;
New Complex Functions
New Complex functions
use Math (complexf, complex);
# Complex_2f
my $z = complexf(1.5f, 1.7f);
# Complex_2d
my $z = complex(1.5, 1.7);
Complex Operation
float Complex Addition, Subtract, Multiply, Scalar Multiply, Division
float Complex Addition, Subtract, Multiply, Scalar Multiply, Division.
# float Addition, Subtract, Multiply, Scalar Multiply, Division functions
use Math(caddf, csubf, cmulf, cscamulf, cdivf);
my $z1 = complexf(1.5f, 1.7f);
my $z2 = complexf(2.5f, 2.7f);
# Addition
my $z_add = caddf($z1, $z2);
# Subtract
my $z_method = csubf($z1, $z2);
# Multiply
my $z_mul = cmulf($z1, $z2);
# Scalar Multiply
my $z_scamul = cscamulf(3, $z2);
# Division
my $z_div = cdivf($z1, $z2);
double Complex Addition, Subtract, Multiply, Scalar Multiply, Division
# double Addition, Subtract, Multiply, Scalar Multiply, Division functions
use Math(cadd, csub, cmul, cscamul, cdiv);
my $z1 = complex(1.5, 1.7);
my $z2 = complex(2.5, 2.7);
# Addition
my $z_add = cadd($z1, $z2);
# Subtract
my $z_method = csub($z1, $z2);
# Multiply
my $z_mul = cmul($z1, $z2);
# Scalar Multiply
my $z_scamul = cscamul(3, $z2);
# Division
my $z_div = cdiv($z1, $z2);
Trigonometric functions
Trigonometric functions.
float Trigonometric functions
float Trigonometric functions.
# float Trigonometric functions
use Math(csinf, ccosf, ctanf);
my $z = complexf(1.5f, 1.7f);
# Addition
my $z_sin = csinf($z);
# Subtract
my $z_cos = ccosf($z);
# Multiply
my $z_tan = ctanf($z);
double Trigonometric functions
double Trigonometric functions.
# double Trigonometric functions
use Math(csin, ccos, ctan);
my $z = complex(1.5, 1.7);
# Addition
my $z_sin = csin($z);
# Subtract
my $z_cos = ccos($z);
# Multiply
my $z_tan = ctan($z);
See Math for more complex functions
Complex Array
SPVM Array of Complex has values arranged in contiguous memory areas.
Complex_2f[]
# Complex float type
use Complex_2f;
my $zs = new Complex_2f[100];
for (my $i = 0; $i < @$zs; $i++) {
my $z = $zs->[$i];
$z->{re} = 1.5f;
$z->{im} = 1.7f;
}
Complex_2d
# Complex double type
use Complex_2d;
my $zs = new Complex_2d[100];
for (my $i = 0; $i < @$zs; $i++) {
my $z = $zs->[$i];
$z->{re} = 1.5;
$z->{im} = 1.7;
}
Call complex function from Perl
Call complex function from Perl. Argument is passed and return value is return.
use SPVM 'MyComplex';
my $z1 = {re => 1.7, im => 2.7};
my $z2 = {re => 7.5, im => 2.5};
my $z_ret = MyComplex->complex_call_from_perl($z1, $z2);
print "($z_ret->{re}, $z_ret->{im})\n";