pelemay
pelemay copied to clipboard
Support elem function
Is your feature request related to a problem? Please describe.
In conv2d: https://github.com/zeam-vm/conv2d
To enhance to use Pelemay:
git diff
:
diff --git a/lib/conv2d.ex b/lib/conv2d.ex
index c6dd785..aeb15da 100644
--- a/lib/conv2d.ex
+++ b/lib/conv2d.ex
@@ -1,4 +1,7 @@
defmodule Conv2d do
+ require Pelemay
+ import Pelemay
+
@moduledoc """
Documentation for Conv2d.
"""
@@ -93,7 +96,7 @@ defmodule Conv2d do
t_input = input |> dup(m) |> t1
t_weight = weight |> t1
- mult = Enum.zip(t_input, t_weight) |> Enum.map(& elem(&1, 0) * elem(&1, 1))
+ mult = Enum.zip(t_input, t_weight) |> map_mult()
mult
|> Enum.chunk_every(x * y)
@@ -105,6 +108,12 @@ defmodule Conv2d do
|> List.flatten
end
+ defpelemay do
+ def map_mult list do
+ list |> Enum.map(& elem(&1, 0) * elem(&1, 1))
+ end
+ end
+
@doc """
## Examples
diff --git a/mix.exs b/mix.exs
index aa86e28..af448e2 100644
--- a/mix.exs
+++ b/mix.exs
@@ -4,8 +4,8 @@ defmodule Conv2d.MixProject do
def project do
[
app: :conv2d,
- version: "0.0.1",
- elixir: "~> 1.7",
+ version: "0.0.2",
+ elixir: "~> 1.9",
start_permanent: Mix.env() == :prod,
deps: deps()
]
@@ -21,6 +21,8 @@ defmodule Conv2d.MixProject do
# Run "mix help deps" to learn about dependencies.
defp deps do
[
+ {:pelemay, "~> 0.0.2"},
+ {:benchfella, "~> 0.3.0", only: :dev},
# {:dep_from_hexpm, "~> 0.3.0"},
# {:dep_from_git, git: "https://github.com/elixir-lang/my_dep.git", tag: "0.1.0"},
]
The following error occurs:
$ mix compile
Compiling 1 file (.ex)
== Compilation error in file lib/conv2d.ex ==
** (ArgumentError) cannot pipe list into elem(&1, 0) * elem(&1, 1), the :* operator can only take two arguments
(elixir) lib/macro.ex:155: Macro.pipe/3
(stdlib) lists.erl:1263: :lists.foldl/3
(elixir) lib/enum.ex:1336: Enum."-map/2-lists^map/1-0-"/2
lib/sum_mag.ex:261: SumMag.optimize_func/2
(elixir) lib/enum.ex:1336: Enum."-map/2-lists^map/1-0-"/2
lib/sum_mag.ex:253: SumMag.map/2
expanding macro: Pelemay.defpelemay/1
lib/conv2d.ex:111: Conv2d (module)
Describe the solution you'd like
Support elem
function in defpelemay
.
Describe alternatives you've considered No idea.
Additional context None.
@hisaway I'll write ideal generated native code, soon later.
@hisaway The following code is ideal generated native code, though I haven't test yet (new code fragments are enif_get_2_double_vec_from_number_tuple_list
and map_mult_elem_2
):
// This file was generated by Pelemay.Generator.Native
#include<stdbool.h>
#include<erl_nif.h>
#include<string.h>
static int load(ErlNifEnv *env, void **priv, ERL_NIF_TERM info);
static void unload(ErlNifEnv *env, void *priv);
static int reload(ErlNifEnv *env, void **priv, ERL_NIF_TERM info);
static int upgrade(ErlNifEnv *env, void **priv, void **old_priv, ERL_NIF_TERM info);
static int
load(ErlNifEnv *env, void **priv, ERL_NIF_TERM info)
{
return 0;
}
static void
unload(ErlNifEnv *env, void *priv)
{
}
static int
reload(ErlNifEnv *env, void **priv, ERL_NIF_TERM info)
{
return 0;
}
static int
upgrade(ErlNifEnv *env, void **priv, void **old_priv, ERL_NIF_TERM info)
{
return load(env, priv, info);
}
const int fail = 0;
const int success = 1;
const int empty = 0;
const size_t cache_line_size = 64;
const size_t size_t_max = -1;
const size_t init_size_long = cache_line_size / sizeof(long);
const size_t init_size_double = cache_line_size / sizeof(double);
const size_t size_t_highest_bit = ~(size_t_max >> 1);
#define loop_vectorize_width 4
int enif_get_long_vec_from_list(ErlNifEnv *env, ERL_NIF_TERM list, long **vec, size_t *vec_l);
int enif_get_double_vec_from_list(ErlNifEnv *env, ERL_NIF_TERM list, double **vec, size_t *vec_l);
int enif_get_double_vec_from_number_list(ErlNifEnv *env, ERL_NIF_TERM list, double **vec, size_t *vec_l);
int enif_get_2_double_vec_from_number_tuple_list(ErlNifEnv *env, ERL_NIF_TERM list, double **vec1, double **vec2, size_t *vec_l);
ERL_NIF_TERM enif_make_list_from_long_vec(ErlNifEnv *env, const long *vec, const size_t vec_l);
ERL_NIF_TERM enif_make_list_from_double_vec(ErlNifEnv *env, const double *vec, const size_t vec_l);
ERL_NIF_TERM
enif_make_list_from_long_vec(ErlNifEnv *env, const long *vec, const size_t vec_l)
{
ERL_NIF_TERM list = enif_make_list(env, 0);
for(size_t i = vec_l; i > 0; i--) {
ERL_NIF_TERM tail = list;
ERL_NIF_TERM head = enif_make_int64(env, vec[i - 1]);
list = enif_make_list_cell(env, head, tail);
}
return list;
}
ERL_NIF_TERM
enif_make_list_from_double_vec(ErlNifEnv *env, const double *vec, const size_t vec_l)
{
ERL_NIF_TERM list = enif_make_list(env, 0);
for(size_t i = vec_l; i > 0; i--) {
ERL_NIF_TERM tail = list;
ERL_NIF_TERM head = enif_make_double(env, vec[i - 1]);
list = enif_make_list_cell(env, head, tail);
}
return list;
}
int
enif_get_long_vec_from_list(ErlNifEnv *env, ERL_NIF_TERM list, long **vec, size_t *vec_l)
{
ERL_NIF_TERM head, tail;
if (__builtin_expect((enif_get_list_cell(env, list, &head, &tail) == fail),
true)) {
if (__builtin_expect((enif_is_empty_list(env, list) == success), true)) {
*vec_l = empty;
*vec = NULL;
return success;
}
return fail;
}
size_t n = init_size_long;
size_t nn = cache_line_size;
long *t = (long *)enif_alloc(nn);
if (__builtin_expect((t == NULL), false)) {
return fail;
}
size_t i = 0;
ERL_NIF_TERM tmp[loop_vectorize_width];
int tmp_r[loop_vectorize_width];
while (true) {
#pragma clang loop vectorize(disable)
for (size_t count = 0; count < loop_vectorize_width; count++) {
tmp[count] = head;
if (__builtin_expect(
(enif_get_list_cell(env, tail, &head, &tail) == fail), false)) {
for (size_t c = 0; c <= count; c++) {
tmp_r[c] = enif_get_int64(env, tmp[c], &t[i++]);
}
int acc = true;
#pragma clang loop vectorize(enable)
for (size_t c = 0; c <= count; c++) {
acc &= (tmp_r[c] == success);
}
if (__builtin_expect((acc == false), false)) {
enif_free(t);
return fail;
}
*vec_l = i;
*vec = t;
return success;
}
}
if (__builtin_expect((i > size_t_max - loop_vectorize_width), false)) {
enif_free(t);
return fail;
}
if (__builtin_expect((i + loop_vectorize_width > n), false)) {
size_t old_nn = nn;
if (__builtin_expect(((nn & size_t_highest_bit) == 0), true)) {
nn <<= 1;
n <<= 1;
} else {
nn = size_t_max;
n = nn / sizeof(long);
}
long *new_t = (long *)enif_alloc(nn);
if(__builtin_expect((new_t == NULL), false)) {
enif_free(t);
return fail;
}
memcpy(new_t, t, old_nn);
enif_free(t);
t = new_t;
}
#pragma clang loop vectorize(enable) unroll(enable)
for (size_t count = 0; count < loop_vectorize_width; count++) {
tmp_r[count] = enif_get_int64(env, tmp[count], &t[i + count]);
}
int acc = true;
#pragma clang loop vectorize(enable) unroll(enable)
for (size_t count = 0; count < loop_vectorize_width; count++) {
acc &= (tmp_r[count] == success);
}
if (__builtin_expect((acc == false), false)) {
enif_free(t);
return fail;
}
i += loop_vectorize_width;
}
}
int
enif_get_double_vec_from_list(ErlNifEnv *env, ERL_NIF_TERM list, double **vec, size_t *vec_l)
{
ERL_NIF_TERM head, tail;
if (__builtin_expect((enif_get_list_cell(env, list, &head, &tail) == fail),
true)) {
if (__builtin_expect((enif_is_empty_list(env, list) == success), true)) {
*vec_l = empty;
*vec = NULL;
return success;
}
return fail;
}
size_t n = init_size_long;
size_t nn = cache_line_size;
double *t = (double *)enif_alloc(nn);
if (__builtin_expect((t == NULL), false)) {
return fail;
}
size_t i = 0;
ERL_NIF_TERM tmp[loop_vectorize_width];
int tmp_r[loop_vectorize_width];
while (true) {
#pragma clang loop vectorize(disable)
for (size_t count = 0; count < loop_vectorize_width; count++) {
tmp[count] = head;
if (__builtin_expect(
(enif_get_list_cell(env, tail, &head, &tail) == fail), false)) {
for (size_t c = 0; c <= count; c++) {
tmp_r[c] = enif_get_double(env, tmp[c], &t[i++]);
}
int acc = true;
#pragma clang loop vectorize(enable)
for (size_t c = 0; c <= count; c++) {
acc &= (tmp_r[c] == success);
}
if (__builtin_expect((acc == false), false)) {
enif_free(t);
return fail;
}
*vec_l = i;
*vec = t;
return success;
}
}
if (__builtin_expect((i > size_t_max - loop_vectorize_width), false)) {
enif_free(t);
return fail;
}
if (__builtin_expect((i + loop_vectorize_width > n), false)) {
size_t old_nn = nn;
if (__builtin_expect(((nn & size_t_highest_bit) == 0), true)) {
nn <<= 1;
n <<= 1;
} else {
nn = size_t_max;
n = nn / sizeof(long);
}
double *new_t = (double *)enif_alloc(nn);
if(__builtin_expect((new_t == NULL), false)) {
enif_free(t);
return fail;
}
memcpy(new_t, t, old_nn);
enif_free(t);
t = new_t;
}
#pragma clang loop vectorize(enable) unroll(enable)
for (size_t count = 0; count < loop_vectorize_width; count++) {
tmp_r[count] = enif_get_double(env, tmp[count], &t[i + count]);
}
int acc = true;
#pragma clang loop vectorize(enable) unroll(enable)
for (size_t count = 0; count < loop_vectorize_width; count++) {
acc &= (tmp_r[count] == success);
}
if (__builtin_expect((acc == false), false)) {
enif_free(t);
return fail;
}
i += loop_vectorize_width;
}
}
int
enif_get_double_vec_from_number_list(ErlNifEnv *env, ERL_NIF_TERM list, double **vec, size_t *vec_l)
{
ERL_NIF_TERM head, tail;
if (__builtin_expect((enif_get_list_cell(env, list, &head, &tail) == fail),
true)) {
if (__builtin_expect((enif_is_empty_list(env, list) == success), true)) {
*vec_l = empty;
*vec = NULL;
return success;
}
return fail;
}
size_t n = init_size_long;
size_t nn = cache_line_size;
double *t = (double *)enif_alloc(nn);
if (__builtin_expect((t == NULL), false)) {
return fail;
}
size_t i = 0;
while (true) {
if (__builtin_expect((enif_get_double(env, head, &t[i]) == fail), false)) {
long tmp;
if (__builtin_expect((enif_get_int64(env, head, &tmp) == fail), false)) {
enif_free(t);
return fail;
}
t[i] = (double)tmp;
}
i++;
if (__builtin_expect(
(enif_get_list_cell(env, tail, &head, &tail) == fail), false)) {
*vec_l = i;
*vec = t;
return success;
}
if (__builtin_expect((i >= n), false)) {
size_t old_nn = nn;
if (__builtin_expect(((nn & size_t_highest_bit) == 0), true)) {
nn <<= 1;
n <<= 1;
} else {
nn = size_t_max;
n = nn / sizeof(long);
}
double *new_t = (double *)enif_alloc(nn);
if (__builtin_expect((new_t == NULL), false)) {
enif_free(t);
return fail;
}
memcpy(new_t, t, old_nn);
enif_free(t);
t = new_t;
}
}
}
int
enif_get_2_double_vec_from_number_tuple_list(ErlNifEnv *env, ERL_NIF_TERM list, double **vec1, double **vec2, size_t *vec_l)
{
ERL_NIF_TERM head, tail;
if (__builtin_expect((enif_get_list_cell(env, list, &head, &tail) == fail),
true)) {
if (__builtin_expect((enif_is_empty_list(env, list) == success), true)) {
*vec_l = empty;
*vec1 = NULL;
*vec2 = NULL;
return success;
}
return fail;
}
size_t n = init_size_long;
size_t nn = cache_line_size;
double *t1 = (double *)enif_alloc(nn);
if (__builtin_expect((t1 == NULL), false)) {
return fail;
}
double *t2 = (double *)enif_alloc(nn);
if (__builtin_expect((t2 == NULL), false)) {
return fail;
}
size_t i = 0;
while (true) {
const ERL_NIF_TERM *tuple;
int arity;
if (__builtin_expect((enif_get_tuple(env, head, &arity, &tuple) == fail), false)) {
enif_free(t1);
enif_free(t2);
return fail;
}
if(__builtin_expect((arity != 2), false)) {
enif_free(t1);
enif_free(t2);
return fail;
}
if (__builtin_expect((enif_get_double(env, tuple[0], &t1[i]) == fail), false)) {
long tmp;
if (__builtin_expect((enif_get_int64(env, tuple[0], &tmp) == fail), false)) {
enif_free(t1);
enif_free(t2);
return fail;
}
t1[i] = (double)tmp;
}
if (__builtin_expect((enif_get_double(env, tuple[1], &t2[i]) == fail), false)) {
long tmp;
if (__builtin_expect((enif_get_int64(env, tuple[1], &tmp) == fail), false)) {
enif_free(t1);
enif_free(t2);
return fail;
}
t2[i] = (double)tmp;
}
i++;
if (__builtin_expect(
(enif_get_list_cell(env, tail, &head, &tail) == fail), false)) {
*vec_l = i;
*vec1 = t1;
*vec2 = t2;
return success;
}
if (__builtin_expect((i >= n), false)) {
size_t old_nn = nn;
if (__builtin_expect(((nn & size_t_highest_bit) == 0), true)) {
nn <<= 1;
n <<= 1;
} else {
nn = size_t_max;
n = nn / sizeof(long);
}
double *new_t = (double *)enif_alloc(nn);
if (__builtin_expect((new_t == NULL), false)) {
enif_free(t1);
enif_free(t2);
return fail;
}
memcpy(new_t, t1, old_nn);
enif_free(t1);
t1 = new_t;
new_t = (double *)enif_alloc(nn);
if (__builtin_expect((new_t == NULL), false)) {
enif_free(t1);
enif_free(t2);
return fail;
}
memcpy(new_t, t2, old_nn);
enif_free(t2);
t2 = new_t;
}
}
}
static ERL_NIF_TERM
map_mult_elem_2(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[])
{
if (__builtin_expect((argc != 1), false)) {
return enif_make_badarg(env);
}
size_t vec_l;
double *vec_1, *vec_2;
if (__builtin_expect((enif_get_2_double_vec_from_number_tuple_list(env, argv[0], &vec_1, &vec_2, &vec_l) == fail), false)) {
return enif_make_badarg(env);
}
#pragma clang loop vectorize_width(loop_vectorize_width)
for(size_t i = 0; i < vec_l; i++) {
vec_1[i] = ((vec_1[i]) * (vec_2[i]));
}
return enif_make_list_from_double_vec(env, vec_1, vec_l);
}
static
ErlNifFunc nif_funcs[] =
{
// {erl_function_name, erl_function_arity, c_function}
{"map_mult_elem_2", 1, map_mult_elem_2},
};
ERL_NIF_INIT(Elixir.PelemayNifElixirAnnexDataList2D, nif_funcs, &load, &reload, &upgrade, &unload)