diff options
author | Lukas Larsson <[email protected]> | 2011-08-02 11:52:53 +0200 |
---|---|---|
committer | Lukas Larsson <[email protected]> | 2011-08-02 11:52:53 +0200 |
commit | b16af6d09ef2a5843e1fb491114906780f3f970d (patch) | |
tree | 484e6102aedf6a70ed8523ad59a7a29478b48c44 | |
parent | 97f867992aaf98eac44c8fcd17df3a15e4aa3eab (diff) | |
parent | f2490767798cbc3ea94d603afb75be2eb65fe564 (diff) | |
download | otp-b16af6d09ef2a5843e1fb491114906780f3f970d.tar.gz otp-b16af6d09ef2a5843e1fb491114906780f3f970d.tar.bz2 otp-b16af6d09ef2a5843e1fb491114906780f3f970d.zip |
Merge branch 'lukas/asn1/ber_encode_nif/OTP-9441' into major
* lukas/asn1/ber_encode_nif/OTP-9441:
Update to use enif_alloc instead of malloc
Make performance code more generic and migrate per/ber NBAP perormance suites to use the generic code
Update code genaration to call nif/erlang depending on what is configured
Remove export_all and only export is_nif_loadable
Add documentation for ber encode nif optmization
Fix bug in counting length of empty composite types
Fix bug where composite types with more then one element would be encoded in reverse
Add pubkey performance tests
Update ber encode nif to use a linked list memry buffer
Create a nif for ber encode
Extract generic is_nif_loadable function from decode
-rw-r--r-- | lib/asn1/c_src/asn1_erl_nif.c | 432 | ||||
-rw-r--r-- | lib/asn1/doc/src/asn1_ug.xml | 4 | ||||
-rw-r--r-- | lib/asn1/doc/src/asn1ct.xml | 10 | ||||
-rw-r--r-- | lib/asn1/src/asn1ct_constructed_ber_bin_v2.erl | 4 | ||||
-rw-r--r-- | lib/asn1/src/asn1ct_gen_ber_bin_v2.erl | 17 | ||||
-rw-r--r-- | lib/asn1/src/asn1rt_ber_bin_v2.erl | 78 | ||||
-rw-r--r-- | lib/asn1/src/asn1rt_nif.erl | 8 | ||||
-rw-r--r-- | lib/asn1/test/asn1_bin_v2_particular_SUITE.erl.src | 258 |
8 files changed, 590 insertions, 221 deletions
diff --git a/lib/asn1/c_src/asn1_erl_nif.c b/lib/asn1/c_src/asn1_erl_nif.c index 58314e23c2..9c9f83bc2a 100644 --- a/lib/asn1/c_src/asn1_erl_nif.c +++ b/lib/asn1/c_src/asn1_erl_nif.c @@ -46,10 +46,6 @@ #define ASN1_PRIMITIVE 0 #define ASN1_CONSTRUCTED 0x20 -#define ASN1_COMPLETE 1 -#define ASN1_BER_TLV_DECODE 2 -#define ASN1_BER_TLV_PARTIAL_DECODE 3 - #define ASN1_NOVALUE 0 #define ASN1_SKIPPED 0 @@ -61,38 +57,55 @@ #define INVMASK(X,M) (X & (M ^ 0xff)) #define MASK(X,M) (X & M) -int complete(ErlNifBinary *, unsigned char *, int ); +/* PER COMPLETE */ +int per_complete(ErlNifBinary *, unsigned char *, int); -int insert_octets(int, unsigned char **, unsigned char **, int *); +int per_insert_octets(int, unsigned char **, unsigned char **, int *); -int insert_octets_except_unused(int, unsigned char **, unsigned char **, int *, - int); +int per_insert_octets_except_unused(int, unsigned char **, unsigned char **, + int *, int); -int insert_octets_as_bits_exact_len(int, int, unsigned char **, +int per_insert_octets_as_bits_exact_len(int, int, unsigned char **, unsigned char **, int *); -int insert_octets_as_bits(int, unsigned char **, unsigned char **, int *); +int per_insert_octets_as_bits(int, unsigned char **, unsigned char **, int *); -int pad_bits(int, unsigned char **, int *); +int per_pad_bits(int, unsigned char **, int *); -int insert_least_sign_bits(int, unsigned char, unsigned char **, int *); +int per_insert_least_sign_bits(int, unsigned char, unsigned char **, int *); -int insert_most_sign_bits(int, unsigned char, unsigned char **, int *); +int per_insert_most_sign_bits(int, unsigned char, unsigned char **, int *); -int insert_bits_as_bits(int, int, unsigned char **, unsigned char **, int *); +int per_insert_bits_as_bits(int, int, unsigned char **, unsigned char **, int *); -int insert_octets_unaligned(int, unsigned char **, unsigned char **, int); +int per_insert_octets_unaligned(int, unsigned char **, unsigned char **, int); -int realloc_memory(ErlNifBinary *, int, unsigned char **); +int per_realloc_memory(ErlNifBinary *, int, unsigned char **); -int decode_begin(ErlNifEnv *, ERL_NIF_TERM *, unsigned char *, int, +/* BER DECODE */ +int ber_decode_begin(ErlNifEnv *, ERL_NIF_TERM *, unsigned char *, int, unsigned int *); -int decode(ErlNifEnv *, ERL_NIF_TERM *, unsigned char *, int *, int); +int ber_decode(ErlNifEnv *, ERL_NIF_TERM *, unsigned char *, int *, int); + +int ber_decode_tag(ErlNifEnv *, ERL_NIF_TERM *, unsigned char *, int, int *); + +int ber_decode_value(ErlNifEnv*, ERL_NIF_TERM *, unsigned char *, int *, int, + int); + +/* BER ENCODE */ +typedef struct ber_encode_mem_chunk mem_chunk_t; + +int ber_encode(ErlNifEnv *, ERL_NIF_TERM , mem_chunk_t **, unsigned int *); -int decode_tag(ErlNifEnv *, ERL_NIF_TERM *, unsigned char *, int, int *); +void ber_free_chunks(mem_chunk_t *chunk); +mem_chunk_t *ber_new_chunk(unsigned int length); +int ber_check_memory(mem_chunk_t **curr, unsigned int needed); -int decode_value(ErlNifEnv*, ERL_NIF_TERM *, unsigned char *, int *, int, int); +int ber_encode_tag(ErlNifEnv *, ERL_NIF_TERM , unsigned int , + mem_chunk_t **, unsigned int *); + +int ber_encode_length(size_t , mem_chunk_t **, unsigned int *); /* * @@ -101,7 +114,8 @@ int decode_value(ErlNifEnv*, ERL_NIF_TERM *, unsigned char *, int *, int, int); * */ -int complete(ErlNifBinary *out_binary, unsigned char *in_buf, int in_buf_len) { +int per_complete(ErlNifBinary *out_binary, unsigned char *in_buf, + int in_buf_len) { int counter = in_buf_len; /* counter keeps track of number of bytes left in the input buffer */ @@ -175,7 +189,7 @@ int complete(ErlNifBinary *out_binary, unsigned char *in_buf, int in_buf_len) { no_bits = (int) *(++in_ptr); val = *(++in_ptr); counter -= 2; - if ((ret = insert_least_sign_bits(no_bits, val, &ptr, &unused)) + if ((ret = per_insert_least_sign_bits(no_bits, val, &ptr, &unused)) == ASN1_ERROR ) return ASN1_ERROR; @@ -189,8 +203,8 @@ int complete(ErlNifBinary *out_binary, unsigned char *in_buf, int in_buf_len) { no_bytes = (int) *(++in_ptr); counter -= (no_bytes + 1); if ((counter < 0) - || (ret = insert_octets(no_bytes, &in_ptr, &ptr, &unused)) - == ASN1_ERROR + || (ret = per_insert_octets(no_bytes, &in_ptr, &ptr, + &unused)) == ASN1_ERROR ) return ASN1_ERROR; buf_space -= ret; @@ -205,8 +219,8 @@ int complete(ErlNifBinary *out_binary, unsigned char *in_buf, int in_buf_len) { no_bytes = no_bytes | (int) *(++in_ptr); counter -= (2 + no_bytes); if ((counter < 0) - || (ret = insert_octets(no_bytes, &in_ptr, &ptr, &unused)) - == ASN1_ERROR + || (ret = per_insert_octets(no_bytes, &in_ptr, &ptr, + &unused)) == ASN1_ERROR ) return ASN1_ERROR; buf_space -= ret; @@ -222,7 +236,7 @@ int complete(ErlNifBinary *out_binary, unsigned char *in_buf, int in_buf_len) { counter -= (2 + no_bytes); ret = -4711; if ((counter < 0) - || (ret = insert_octets_except_unused(no_bytes, &in_ptr, + || (ret = per_insert_octets_except_unused(no_bytes, &in_ptr, &ptr, &unused, in_unused)) == ASN1_ERROR ) return ASN1_ERROR; @@ -241,7 +255,7 @@ int complete(ErlNifBinary *out_binary, unsigned char *in_buf, int in_buf_len) { no_bytes = no_bytes | (int) *(++in_ptr); counter -= (3 + no_bytes); if ((counter < 0) - || (ret = insert_octets_except_unused(no_bytes, &in_ptr, + || (ret = per_insert_octets_except_unused(no_bytes, &in_ptr, &ptr, &unused, in_unused)) == ASN1_ERROR ) return ASN1_ERROR; @@ -273,15 +287,14 @@ int complete(ErlNifBinary *out_binary, unsigned char *in_buf, int in_buf_len) { /* Have to allocate more memory */ buf_size += needed; buf_space += needed; - if (realloc_memory(out_binary, buf_size, &ptr) - == ASN1_ERROR - ) + if (per_realloc_memory(out_binary, buf_size, &ptr) == ASN1_ERROR + ) return ASN1_ERROR; } counter -= (2 + no_bytes); if ((counter < 0) - || (ret = insert_octets_as_bits_exact_len(desired_len, + || (ret = per_insert_octets_as_bits_exact_len(desired_len, no_bytes, &in_ptr, &ptr, &unused)) == ASN1_ERROR ) return ASN1_ERROR; @@ -302,15 +315,14 @@ int complete(ErlNifBinary *out_binary, unsigned char *in_buf, int in_buf_len) { /* Have to allocate more memory */ buf_size += needed; buf_space += needed; - if (realloc_memory(out_binary, buf_size, &ptr) - == ASN1_ERROR - ) + if (per_realloc_memory(out_binary, buf_size, &ptr) == ASN1_ERROR + ) return ASN1_ERROR; } counter -= (3 + no_bytes); if ((counter < 0) - || (ret = insert_octets_as_bits_exact_len(desired_len, + || (ret = per_insert_octets_as_bits_exact_len(desired_len, no_bytes, &in_ptr, &ptr, &unused)) == ASN1_ERROR ) return ASN1_ERROR; @@ -331,15 +343,14 @@ int complete(ErlNifBinary *out_binary, unsigned char *in_buf, int in_buf_len) { /* Have to allocate more memory */ buf_size += needed; buf_space += needed; - if (realloc_memory(out_binary, buf_size, &ptr) - == ASN1_ERROR - ) + if (per_realloc_memory(out_binary, buf_size, &ptr) == ASN1_ERROR + ) return ASN1_ERROR; } counter -= (3 + no_bytes); if ((counter < 0) - || (ret = insert_octets_as_bits_exact_len(desired_len, + || (ret = per_insert_octets_as_bits_exact_len(desired_len, no_bytes, &in_ptr, &ptr, &unused)) == ASN1_ERROR ) return ASN1_ERROR; @@ -362,15 +373,14 @@ int complete(ErlNifBinary *out_binary, unsigned char *in_buf, int in_buf_len) { /* Have to allocate more memory */ buf_size += needed; buf_space += needed; - if (realloc_memory(out_binary, buf_size, &ptr) - == ASN1_ERROR - ) + if (per_realloc_memory(out_binary, buf_size, &ptr) == ASN1_ERROR + ) return ASN1_ERROR; } counter -= (4 + no_bytes); if ((counter < 0) - || (ret = insert_octets_as_bits_exact_len(desired_len, + || (ret = per_insert_octets_as_bits_exact_len(desired_len, no_bytes, &in_ptr, &ptr, &unused)) == ASN1_ERROR ) return ASN1_ERROR; @@ -392,16 +402,15 @@ int complete(ErlNifBinary *out_binary, unsigned char *in_buf, int in_buf_len) { /* Have to allocate more memory */ buf_size += needed; buf_space += needed; - if (realloc_memory(out_binary, buf_size, &ptr) - == ASN1_ERROR - ) + if (per_realloc_memory(out_binary, buf_size, &ptr) == ASN1_ERROR + ) return ASN1_ERROR; } counter -= (2 + no_bytes); if ((counter < 0) - || (ret = insert_bits_as_bits(desired_len, no_bytes, + || (ret = per_insert_bits_as_bits(desired_len, no_bytes, &in_ptr, &ptr, &unused)) == ASN1_ERROR ) return ASN1_ERROR; @@ -422,15 +431,14 @@ int complete(ErlNifBinary *out_binary, unsigned char *in_buf, int in_buf_len) { /* Have to allocate more memory */ buf_size += needed; buf_space += needed; - if (realloc_memory(out_binary, buf_size, &ptr) - == ASN1_ERROR - ) + if (per_realloc_memory(out_binary, buf_size, &ptr) == ASN1_ERROR + ) return ASN1_ERROR; } counter -= (3 + no_bytes); if ((counter < 0) - || (ret = insert_bits_as_bits(desired_len, no_bytes, + || (ret = per_insert_bits_as_bits(desired_len, no_bytes, &in_ptr, &ptr, &unused)) == ASN1_ERROR ) return ASN1_ERROR; @@ -453,15 +461,14 @@ int complete(ErlNifBinary *out_binary, unsigned char *in_buf, int in_buf_len) { /* Have to allocate more memory */ buf_size += needed; buf_space += needed; - if (realloc_memory(out_binary, buf_size, &ptr) - == ASN1_ERROR - ) + if (per_realloc_memory(out_binary, buf_size, &ptr) == ASN1_ERROR + ) return ASN1_ERROR; } counter -= (4 + no_bytes); if ((counter < 0) - || (ret = insert_bits_as_bits(desired_len, no_bytes, + || (ret = per_insert_bits_as_bits(desired_len, no_bytes, &in_ptr, &ptr, &unused)) == ASN1_ERROR ) return ASN1_ERROR; @@ -483,7 +490,7 @@ int complete(ErlNifBinary *out_binary, unsigned char *in_buf, int in_buf_len) { } } -int realloc_memory(ErlNifBinary *binary, int amount, unsigned char **ptr) { +int per_realloc_memory(ErlNifBinary *binary, int amount, unsigned char **ptr) { int i = *ptr - binary->data; @@ -496,7 +503,7 @@ int realloc_memory(ErlNifBinary *binary, int amount, unsigned char **ptr) { return ASN1_OK; } -int insert_most_sign_bits(int no_bits, unsigned char val, +int per_insert_most_sign_bits(int no_bits, unsigned char val, unsigned char **output_ptr, int *unused) { unsigned char *ptr = *output_ptr; @@ -517,7 +524,7 @@ int insert_most_sign_bits(int no_bits, unsigned char val, return ASN1_OK; } -int insert_least_sign_bits(int no_bits, unsigned char val, +int per_insert_least_sign_bits(int no_bits, unsigned char val, unsigned char **output_ptr, int *unused) { unsigned char *ptr = *output_ptr; int ret = 0; @@ -543,10 +550,10 @@ int insert_least_sign_bits(int no_bits, unsigned char val, return ret; } -/* pad_bits adds no_bits bits in the buffer that output_ptr +/* per_pad_bits adds no_bits bits in the buffer that output_ptr points at. */ -int pad_bits(int no_bits, unsigned char **output_ptr, int *unused) { +int per_pad_bits(int no_bits, unsigned char **output_ptr, int *unused) { unsigned char *ptr = *output_ptr; int ret = 0; @@ -569,37 +576,37 @@ int pad_bits(int no_bits, unsigned char **output_ptr, int *unused) { The unused parameter tells how many bits that are not set in the actual byte in the output buffer. If desired_no is more bits than the input buffer has in no_bytes bytes, then zero bits is padded.*/ -int insert_bits_as_bits(int desired_no, int no_bytes, unsigned char **input_ptr, - unsigned char **output_ptr, int *unused) { +int per_insert_bits_as_bits(int desired_no, int no_bytes, + unsigned char **input_ptr, unsigned char **output_ptr, int *unused) { unsigned char *in_ptr = *input_ptr; unsigned char val; int no_bits, ret, ret2; if (desired_no == (no_bytes * 8)) { - if (insert_octets_unaligned(no_bytes, &in_ptr, output_ptr, *unused) + if (per_insert_octets_unaligned(no_bytes, &in_ptr, output_ptr, *unused) == ASN1_ERROR ) return ASN1_ERROR; ret = no_bytes; } else if (desired_no < (no_bytes * 8)) { - /* printf("insert_bits_as_bits 1\n\r"); */ - if (insert_octets_unaligned(desired_no / 8, &in_ptr, output_ptr, + /* printf("per_insert_bits_as_bits 1\n\r"); */ + if (per_insert_octets_unaligned(desired_no / 8, &in_ptr, output_ptr, *unused) == ASN1_ERROR ) return ASN1_ERROR; - /* printf("insert_bits_as_bits 2\n\r"); */ + /* printf("per_insert_bits_as_bits 2\n\r"); */ val = *++in_ptr; /* printf("val = %d\n\r",(int)val); */ no_bits = desired_no % 8; /* printf("no_bits = %d\n\r",no_bits); */ - insert_most_sign_bits(no_bits, val, output_ptr, unused); + per_insert_most_sign_bits(no_bits, val, output_ptr, unused); ret = CEIL(desired_no,8); } else { - if (insert_octets_unaligned(no_bytes, &in_ptr, output_ptr, *unused) + if (per_insert_octets_unaligned(no_bytes, &in_ptr, output_ptr, *unused) == ASN1_ERROR ) return ASN1_ERROR; - ret2 = pad_bits(desired_no - (no_bytes * 8), output_ptr, unused); + ret2 = per_pad_bits(desired_no - (no_bytes * 8), output_ptr, unused); /* printf("ret2 = %d\n\r",ret2); */ ret = CEIL(desired_no,8); /* printf("ret = %d\n\r",ret); */ @@ -609,30 +616,30 @@ int insert_bits_as_bits(int desired_no, int no_bytes, unsigned char **input_ptr, return ret; } -/* insert_octets_as_bits_exact_len */ -int insert_octets_as_bits_exact_len(int desired_len, int in_buff_len, +/* per_insert_octets_as_bits_exact_len */ +int per_insert_octets_as_bits_exact_len(int desired_len, int in_buff_len, unsigned char **in_ptr, unsigned char **ptr, int *unused) { int ret = 0; int ret2 = 0; if (desired_len == in_buff_len) { - if ((ret = insert_octets_as_bits(in_buff_len, in_ptr, ptr, unused)) + if ((ret = per_insert_octets_as_bits(in_buff_len, in_ptr, ptr, unused)) == ASN1_ERROR ) return ASN1_ERROR; } else if (desired_len > in_buff_len) { - if ((ret = insert_octets_as_bits(in_buff_len, in_ptr, ptr, unused)) + if ((ret = per_insert_octets_as_bits(in_buff_len, in_ptr, ptr, unused)) == ASN1_ERROR ) return ASN1_ERROR; /* now pad with zero bits */ /* printf("~npad_bits: called with %d bits padding~n~n~r",desired_len - in_buff_len); */ - if ((ret2 = pad_bits(desired_len - in_buff_len, ptr, unused)) + if ((ret2 = per_pad_bits(desired_len - in_buff_len, ptr, unused)) == ASN1_ERROR ) return ASN1_ERROR; } else {/* desired_len < no_bits */ - if ((ret = insert_octets_as_bits(desired_len, in_ptr, ptr, unused)) + if ((ret = per_insert_octets_as_bits(desired_len, in_ptr, ptr, unused)) == ASN1_ERROR ) return ASN1_ERROR; @@ -648,7 +655,7 @@ int insert_octets_as_bits_exact_len(int desired_len, int in_buff_len, otherwise the function returns ASN1_ERROR. The output buffer is concatenated without alignment. */ -int insert_octets_as_bits(int no_bytes, unsigned char **input_ptr, +int per_insert_octets_as_bits(int no_bytes, unsigned char **input_ptr, unsigned char **output_ptr, int *unused) { unsigned char *in_ptr = *input_ptr; unsigned char *ptr = *output_ptr; @@ -688,7 +695,7 @@ int insert_octets_as_bits(int no_bytes, unsigned char **input_ptr, into the output buffer, *output_ptr. Before the first byte is inserted the input buffer is aligned. */ -int insert_octets(int no_bytes, unsigned char **input_ptr, +int per_insert_octets(int no_bytes, unsigned char **input_ptr, unsigned char **output_ptr, int *unused) { unsigned char *in_ptr = *input_ptr; unsigned char *ptr = *output_ptr; @@ -710,10 +717,10 @@ int insert_octets(int no_bytes, unsigned char **input_ptr, return (ret + no_bytes); } -/* insert_octets_unaligned inserts bytes from the input buffer, *input_ptr, +/* per_insert_octets_unaligned inserts bytes from the input buffer, *input_ptr, into the output buffer, *output_ptr.No alignment is done. */ -int insert_octets_unaligned(int no_bytes, unsigned char **input_ptr, +int per_insert_octets_unaligned(int no_bytes, unsigned char **input_ptr, unsigned char **output_ptr, int unused) { unsigned char *in_ptr = *input_ptr; unsigned char *ptr = *output_ptr; @@ -737,7 +744,7 @@ int insert_octets_unaligned(int no_bytes, unsigned char **input_ptr, return no_bytes; } -int insert_octets_except_unused(int no_bytes, unsigned char **input_ptr, +int per_insert_octets_except_unused(int no_bytes, unsigned char **input_ptr, unsigned char **output_ptr, int *unused, int in_unused) { unsigned char *in_ptr = *input_ptr; unsigned char *ptr = *output_ptr; @@ -745,12 +752,12 @@ int insert_octets_except_unused(int no_bytes, unsigned char **input_ptr, int ret = 0; if (in_unused == 0) { - if ((ret = insert_octets_unaligned(no_bytes, &in_ptr, &ptr, *unused)) + if ((ret = per_insert_octets_unaligned(no_bytes, &in_ptr, &ptr, *unused)) == ASN1_ERROR ) return ASN1_ERROR; } else { - if ((ret = insert_octets_unaligned(no_bytes - 1, &in_ptr, &ptr, *unused)) + if ((ret = per_insert_octets_unaligned(no_bytes - 1, &in_ptr, &ptr, *unused)) != ASN1_ERROR) { val = (int) *(++in_ptr); no_bits = 8 - in_unused; @@ -789,7 +796,7 @@ int insert_octets_except_unused(int no_bytes, unsigned char **input_ptr, /* * int decode(ErlNifEnv* env, ERL_NIF_TERM *term, unsigned char *in_buf, - int in_buf_len, unsigned int *err_pos) + int in_buf_len, unsigned int *err_pos) * term is a pointer to the term which is to be returned to erlang * in_buf is a pointer into the buffer of incoming bytes. * in_buf_len is the length of the incoming buffer. @@ -830,16 +837,16 @@ int insert_octets_except_unused(int no_bytes, unsigned char **input_ptr, * is the empty binary. * If some error occured during the decoding of the in_buf an error is returned. */ -int decode_begin(ErlNifEnv* env, ERL_NIF_TERM *term, unsigned char *in_buf, +int ber_decode_begin(ErlNifEnv* env, ERL_NIF_TERM *term, unsigned char *in_buf, int in_buf_len, unsigned int *err_pos) { int maybe_ret; int ib_index = 0; unsigned char *rest_data; ERL_NIF_TERM decoded_term, rest; - if ((maybe_ret = decode(env, &decoded_term, in_buf, &ib_index, in_buf_len)) - <= ASN1_ERROR) - { + if ((maybe_ret = ber_decode(env, &decoded_term, in_buf, &ib_index, + in_buf_len)) <= ASN1_ERROR) + { *err_pos = ib_index; return maybe_ret; }; @@ -855,7 +862,7 @@ int decode_begin(ErlNifEnv* env, ERL_NIF_TERM *term, unsigned char *in_buf, return ASN1_OK; } -int decode(ErlNifEnv* env, ERL_NIF_TERM *term, unsigned char *in_buf, +int ber_decode(ErlNifEnv* env, ERL_NIF_TERM *term, unsigned char *in_buf, int *ib_index, int in_buf_len) { int maybe_ret; int form; @@ -865,7 +872,7 @@ int decode(ErlNifEnv* env, ERL_NIF_TERM *term, unsigned char *in_buf, if ((*ib_index + 2) > in_buf_len) return ASN1_VALUE_ERROR; /* "{{TagNo," */ - if ((form = decode_tag(env, &tag, in_buf, in_buf_len, ib_index)) + if ((form = ber_decode_tag(env, &tag, in_buf, in_buf_len, ib_index)) <= ASN1_ERROR ) return form; /* 5 bytes */ @@ -875,7 +882,7 @@ int decode(ErlNifEnv* env, ERL_NIF_TERM *term, unsigned char *in_buf, /* buffer must hold at least one byte (0 as length and nothing as value) */ /* "{{TagNo,Value}," */ - if ((maybe_ret = decode_value(env, &value, in_buf, ib_index, form, + if ((maybe_ret = ber_decode_value(env, &value, in_buf, ib_index, form, in_buf_len)) <= ASN1_ERROR ) return maybe_ret; /* at least 5 bytes */ @@ -887,7 +894,7 @@ int decode(ErlNifEnv* env, ERL_NIF_TERM *term, unsigned char *in_buf, * decode_tag decodes the BER encoded tag in in_buf and creates an * nif term tag */ -int decode_tag(ErlNifEnv* env, ERL_NIF_TERM *tag, unsigned char *in_buf, +int ber_decode_tag(ErlNifEnv* env, ERL_NIF_TERM *tag, unsigned char *in_buf, int in_buf_len, int *ib_index) { int tag_no, tmp_tag, form; @@ -930,11 +937,11 @@ int decode_tag(ErlNifEnv* env, ERL_NIF_TERM *tag, unsigned char *in_buf, } /* - * decode_value decodes the BER encoded length and value fields in the + * ber_decode_value decodes the BER encoded length and value fields in the * in_buf and puts the value part in the decode_buf as an Erlang * nif term into value */ -int decode_value(ErlNifEnv* env, ERL_NIF_TERM *value, unsigned char *in_buf, +int ber_decode_value(ErlNifEnv* env, ERL_NIF_TERM *value, unsigned char *in_buf, int *ib_index, int form, int in_buf_len) { int maybe_ret; unsigned int len = 0; @@ -970,7 +977,7 @@ int decode_value(ErlNifEnv* env, ERL_NIF_TERM *value, unsigned char *in_buf, if (*ib_index >= in_buf_len) return ASN1_INDEF_LEN_ERROR; - if ((maybe_ret = decode(env, &term, in_buf, ib_index, in_buf_len)) + if ((maybe_ret = ber_decode(env, &term, in_buf, ib_index, in_buf_len)) <= ASN1_ERROR ) return maybe_ret; @@ -986,9 +993,9 @@ int decode_value(ErlNifEnv* env, ERL_NIF_TERM *value, unsigned char *in_buf, curr_head = enif_make_list(env, 0); while (*ib_index < end_index) { - if ((maybe_ret = decode(env, &term, in_buf, ib_index, in_buf_len)) - <= ASN1_ERROR - ) + if ((maybe_ret = ber_decode(env, &term, in_buf, ib_index, + in_buf_len)) <= ASN1_ERROR + ) return maybe_ret; curr_head = enif_make_list_cell(env, term, curr_head); } @@ -1003,6 +1010,187 @@ int decode_value(ErlNifEnv* env, ERL_NIF_TERM *value, unsigned char *in_buf, return ASN1_OK; } +struct ber_encode_mem_chunk { + mem_chunk_t *next; + int length; + char *top; + char *curr; +}; + +int ber_encode(ErlNifEnv *env, ERL_NIF_TERM term, mem_chunk_t **curr, unsigned int *count) { + + const ERL_NIF_TERM *tv; + unsigned int form; + int arity; + + if (!enif_get_tuple(env, term, &arity, &tv)) + return ASN1_ERROR; + + form = enif_is_list(env, tv[1]) ? ASN1_CONSTRUCTED : ASN1_PRIMITIVE; + + switch (form) { + case ASN1_PRIMITIVE: { + ErlNifBinary value; + if (!enif_inspect_binary(env, tv[1], &value)) + return ASN1_ERROR; + + if (ber_check_memory(curr, value.size)) + return ASN1_ERROR; + memcpy((*curr)->curr - value.size + 1, value.data, value.size); + (*curr)->curr -= value.size; + *count += value.size; + + if (ber_encode_length(value.size, curr, count)) + return ASN1_ERROR; + + break; + } + case ASN1_CONSTRUCTED: { + ERL_NIF_TERM head, tail; + unsigned int tmp_cnt; + + if(!enif_make_reverse_list(env, tv[1], &head)) + return ASN1_ERROR; + + if (!enif_get_list_cell(env, head, &head, &tail)) { + if (enif_is_empty_list(env, tv[1])) { + *((*curr)->curr) = 0; + (*curr)->curr -= 1; + (*count)++; + break; + } else + return ASN1_ERROR; + } + + do { + tmp_cnt = 0; + if (ber_encode(env, head, curr, &tmp_cnt)) { + return ASN1_ERROR; + } + *count += tmp_cnt; + } while (enif_get_list_cell(env, tail, &head, &tail)); + + if (ber_check_memory(curr, *count)) { + return ASN1_ERROR; + } + + if (ber_encode_length(*count, curr, count)) { + return ASN1_ERROR; + } + + break; + } + } + + // We need atleast 5 bytes to encode the next tlv + if (ber_check_memory(curr, 3)) + return ASN1_ERROR; + + if (ber_encode_tag(env, tv[0], form, curr, count)) + return ASN1_ERROR; + + return ASN1_OK; +} + +int ber_encode_tag(ErlNifEnv *env, ERL_NIF_TERM tag, unsigned int form, + mem_chunk_t **curr, unsigned int *count) { + unsigned int class_tag_no, head_tag; + if (!enif_get_uint(env, tag, &class_tag_no)) + return ASN1_ERROR; + + head_tag = form | ((class_tag_no & 0x30000) >> 10); + class_tag_no = class_tag_no & 0xFFFF; + + if (class_tag_no <= 30) { + *(*curr)->curr = head_tag | class_tag_no; + (*curr)->curr -= 1; + (*count)++; + return ASN1_OK; + } else { + *(*curr)->curr = class_tag_no & 127; + class_tag_no = class_tag_no >> 7; + (*curr)->curr -= 1; + (*count)++; + + while (class_tag_no > 0) { + *(*curr)->curr = (class_tag_no & 127) | 0x80; + class_tag_no >>= 7; + (*curr)->curr -= 1; + (*count)++; + } + + *(*curr)->curr = head_tag | 0x1F; + (*curr)->curr -= 1; + (*count)++; + + return ASN1_OK; + } +} + +int ber_encode_length(size_t size, mem_chunk_t **curr, unsigned int *count) { + if (size < 128) { + if (ber_check_memory(curr, 1u)) + return ASN1_ERROR; + *(*curr)->curr = size; + (*curr)->curr -= 1; + (*count)++; + } else { + int chunks = size / 256 + 1; + if (ber_check_memory(curr, chunks + 1)) + return ASN1_ERROR; + + while (size > 0) + { + *(*curr)->curr = size & 0xFF; + size >>= 8; + (*curr)->curr -= 1; + (*count)++; + } + + *(*curr)->curr = chunks | 0x80; + (*curr)->curr -= 1; + (*count)++; + } + return ASN1_OK; +} + +mem_chunk_t *ber_new_chunk(unsigned int length) { + mem_chunk_t *new = enif_alloc(sizeof(mem_chunk_t)); + if (new == NULL) + return NULL; + new->next = NULL; + new->top = enif_alloc(sizeof(char) * length); + if (new->top == NULL) { + free(new); + return NULL; + } + new->curr = new->top + length - 1; + new->length = length; + return new; +} + +void ber_free_chunks(mem_chunk_t *chunk) { + mem_chunk_t *curr, *next = chunk; + while (next != NULL) { + curr = next; + next = curr->next; + enif_free(curr->top); + enif_free(curr); + } +} + +int ber_check_memory(mem_chunk_t **curr, unsigned int needed) { + mem_chunk_t *new; + if ((*curr)->curr-needed >= (*curr)->top) + return ASN1_OK; + + if ((new = ber_new_chunk((*curr)->length > needed ? (*curr)->length * 2 : (*curr)->length + needed)) == NULL) + return ASN1_ERROR; + new->next = *curr; + *curr = new; + return ASN1_OK; +} + static ERL_NIF_TERM encode_per_complete(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { ERL_NIF_TERM err_code; @@ -1018,11 +1206,11 @@ static ERL_NIF_TERM encode_per_complete(ErlNifEnv* env, int argc, if (in_binary.size == 0) return enif_make_binary(env, &out_binary); - if ((complete_len = complete(&out_binary, in_binary.data, in_binary.size)) - <= ASN1_ERROR) { + if ((complete_len = per_complete(&out_binary, in_binary.data, + in_binary.size)) <= ASN1_ERROR) { enif_release_binary(&out_binary); if (complete_len == ASN1_ERROR - ) + ) err_code = enif_make_uint(env, '1'); else err_code = enif_make_uint(env, 0); @@ -1043,7 +1231,7 @@ static ERL_NIF_TERM decode_ber_tlv(ErlNifEnv* env, int argc, if (!enif_inspect_iolist_as_binary(env, argv[0], &in_binary)) return enif_make_badarg(env); - if ((return_code = decode_begin(env, &return_term, in_binary.data, + if ((return_code = ber_decode_begin(env, &return_term, in_binary.data, in_binary.size, &err_pos)) != ASN1_OK ) return enif_make_tuple2(env, enif_make_atom(env,"error"), enif_make_tuple2(env, @@ -1051,6 +1239,43 @@ static ERL_NIF_TERM decode_ber_tlv(ErlNifEnv* env, int argc, return return_term; } +static ERL_NIF_TERM encode_ber_tlv(ErlNifEnv* env, int argc, + const ERL_NIF_TERM argv[]) { + ErlNifBinary out_binary; + unsigned int length = 0, pos = 0; + int encode_err; + mem_chunk_t *curr, *top; + ERL_NIF_TERM err_code; + + curr = ber_new_chunk(40); + + if ((encode_err = ber_encode(env, argv[0], &curr, &length)) + <= ASN1_ERROR) { + ber_free_chunks(curr); + err_code = enif_make_int(env, encode_err); + return enif_make_tuple2(env, enif_make_atom(env, "error"), err_code); + } + + if (!enif_alloc_binary(length, &out_binary)) { + ber_free_chunks(curr); + return enif_make_tuple2(env, enif_make_atom(env, "error"), enif_make_atom(env,"oom")); + } + + top = curr; + + while (curr != NULL) { + length = curr->length - (curr->curr-curr->top) -1; + if (length > 0) + memcpy(out_binary.data + pos, curr->curr+1, length); + pos += length; + curr = curr->next; + } + + ber_free_chunks(top); + + return enif_make_binary(env, &out_binary); +} + static int is_ok_load_info(ErlNifEnv* env, ERL_NIF_TERM load_info) { int i; return enif_get_int(env, load_info, &i) && i == 1; @@ -1074,6 +1299,7 @@ static void unload(ErlNifEnv* env, void* priv_data) { } static ErlNifFunc nif_funcs[] = { { "encode_per_complete", 1, - encode_per_complete }, { "decode_ber_tlv", 1, decode_ber_tlv } }; + encode_per_complete }, { "decode_ber_tlv", 1, decode_ber_tlv }, { + "encode_ber_tlv", 1, encode_ber_tlv } }; ERL_NIF_INIT(asn1rt_nif, nif_funcs, load, NULL, upgrade, unload) diff --git a/lib/asn1/doc/src/asn1_ug.xml b/lib/asn1/doc/src/asn1_ug.xml index 61e4f6062f..1b399fb641 100644 --- a/lib/asn1/doc/src/asn1_ug.xml +++ b/lib/asn1/doc/src/asn1_ug.xml @@ -369,7 +369,7 @@ erlc -o ../asnfiles -I ../asnfiles -I /usr/local/standards/asn1 Person.asn <item> <p>Together with the flags <c>ber_bin</c> and <c>optimize</c> you choose to use a nif for considerable - faster decode. </p> + faster encode and decode. </p> </item> <tag><c>+asn1config</c></tag> <item> @@ -631,7 +631,7 @@ asn1ct:decode('H323-MESSAGES','SomeChoiceType',Bytes). </pre> </table> <p> - The sole compile options <c>ber</c>, <c>ber_bin</c>, <c>per</c> and + The compile options <c>ber</c>, <c>per</c> and <c>driver</c> are kept for backwards compatibility and should not be used in new code. The nif implementation which replaces the linked-in driver has been shown to be about 5-15% faster. diff --git a/lib/asn1/doc/src/asn1ct.xml b/lib/asn1/doc/src/asn1ct.xml index d7c2572dc8..13e6977419 100644 --- a/lib/asn1/doc/src/asn1ct.xml +++ b/lib/asn1/doc/src/asn1ct.xml @@ -225,8 +225,8 @@ Binary = binary() <item> <p>Option valid together with <c>ber_bin</c> and <c>optimize</c> options. It enables the use of several nifs that gives faster - decode. Nifs are only enabled by the explicit use of the option - <c>nif</c></p> + encode and decode. Nifs are only enabled by the explicit use of + the option <c>nif</c></p> </item> <tag><c>asn1config</c></tag> <item> @@ -269,7 +269,11 @@ Binary = binary() <c>.set.asn</c> are exported, unless a <c>{export,[atom()]}</c> or <c>{export_all,true}</c> option are provided. The list of atoms are names of chosen asn1 - specs from the <c>.set.asn</c> file.</p> + specs from the <c>.set.asn</c> file. </p> + <p>When used together with <c>nif</c> for <c>ber_bin</c>, the + asn1 nifs will be used if the <c>asn1rt_nif</c> module is + available. If it is not available, a slower erlang fallback + will be used.</p> </item> <tag><c>inline</c></tag> <item> diff --git a/lib/asn1/src/asn1ct_constructed_ber_bin_v2.erl b/lib/asn1/src/asn1ct_constructed_ber_bin_v2.erl index e16873c717..243ff234a7 100644 --- a/lib/asn1/src/asn1ct_constructed_ber_bin_v2.erl +++ b/lib/asn1/src/asn1ct_constructed_ber_bin_v2.erl @@ -877,13 +877,13 @@ gen_dec_choice(Erules,TopType, _ChTag, CompList, Ext) -> emit([indent(9),"exit({error,{asn1,{invalid_choice_tag,", {curr,else},"}}})",nl]); _ -> - emit([indent(9),"{asn1_ExtAlt, ?RT_BER:encode(",{curr,else},")}",nl]) + emit([indent(9),"{asn1_ExtAlt, ?RT_BER:encode(",{curr,else}, + asn1ct_gen:nif_parameter(),")}",nl]) end, emit([indent(3),"end",nl]), asn1ct_name:new(tag), asn1ct_name:new(else). - gen_dec_choice_cases(_Erules,_TopType, []) -> ok; gen_dec_choice_cases(Erules,TopType, [H|T]) -> diff --git a/lib/asn1/src/asn1ct_gen_ber_bin_v2.erl b/lib/asn1/src/asn1ct_gen_ber_bin_v2.erl index e8a4ad0cf1..781271bae7 100644 --- a/lib/asn1/src/asn1ct_gen_ber_bin_v2.erl +++ b/lib/asn1/src/asn1ct_gen_ber_bin_v2.erl @@ -728,13 +728,13 @@ gen_dec_prim(Erules,Att,BytesVar,DoTag,TagIn,Form,OptOrMand) -> {_,#'ObjectClassFieldType'{}} -> case asn1ct_gen:get_inner(Att#type.def) of 'ASN1_OPEN_TYPE' -> - emit([{asis,DoTag},")"]); + emit([{asis,DoTag},asn1ct_gen:nif_parameter(),")"]); _ -> ok end; {{string,TagStr},'ASN1_OPEN_TYPE'} -> - emit([TagStr,")"]); + emit([TagStr,asn1ct_gen:nif_parameter(),")"]); {_,'ASN1_OPEN_TYPE'} -> - emit([{asis,DoTag},")"]); + emit([{asis,DoTag},asn1ct_gen:nif_parameter(),")"]); {{string,TagStr},_} -> emit([TagStr,")"]); _ when is_list(DoTag) -> @@ -1502,13 +1502,14 @@ gen_objset_dec(Erules,ObjSetName,_UniqueName,['EXTENSIONMARK'],_ClName, _ClFields,_NthObj) -> emit(["'getdec_",ObjSetName,"'(_, _) ->",nl]), emit([indent(2),"fun(_,Bytes, _RestPrimFieldName) ->",nl]), + case Erules of ber_bin_v2 -> emit([indent(4),"case Bytes of",nl, indent(6),"Bin when is_binary(Bin) -> ",nl, indent(8),"Bin;",nl, indent(6),"_ ->",nl, - indent(8),"?RT_BER:encode(Bytes)",nl, + indent(8),"?RT_BER:encode(Bytes",driver_parameter(),")",nl, indent(4),"end",nl]); _ -> emit([indent(6),"Len = case Bytes of",nl,indent(9), @@ -1521,6 +1522,14 @@ gen_objset_dec(Erules,ObjSetName,_UniqueName,['EXTENSIONMARK'],_ClName, gen_objset_dec(_,_,_,[],_,_,_) -> ok. +driver_parameter() -> + Options = get(encoding_options), + case {lists:member(driver,Options),lists:member(nif,Options)} of + {true,_} -> ",nif"; + {_,true} -> ",nif"; + _ -> ",erlang" + end. + emit_default_getdec(ObjSetName,UniqueName) -> emit(["'getdec_",ObjSetName,"'(",{asis,UniqueName},", ErrV) ->",nl]), emit([indent(2), "fun(C,V,_) -> exit({{component,C},{value,V},{unique_name_and_value,",{asis,UniqueName},", ErrV}}) end"]). diff --git a/lib/asn1/src/asn1rt_ber_bin_v2.erl b/lib/asn1/src/asn1rt_ber_bin_v2.erl index 2df289e2b8..bef2216091 100644 --- a/lib/asn1/src/asn1rt_ber_bin_v2.erl +++ b/lib/asn1/src/asn1rt_ber_bin_v2.erl @@ -21,7 +21,7 @@ %% encoding / decoding of BER --export([decode/1, decode/2, match_tags/2, encode/1]). +-export([decode/1, decode/2, match_tags/2, encode/1, encode/2]). -export([fixoptionals/2, cindex/3, list_to_record/2, encode_tag_val/1, @@ -50,10 +50,13 @@ -export([encode_open_type/1,encode_open_type/2, decode_open_type/2,decode_open_type/3, - decode_open_type_as_binary/2]). + decode_open_type_as_binary/2, + decode_open_type_as_binary/3]). -export([decode_primitive_incomplete/2,decode_selective/2]). - + +-export([is_nif_loadable/0]). + -include("asn1_records.hrl"). % the encoding of class of tag bits 8 and 7 @@ -126,15 +129,28 @@ % encode(Tlv) -> % encode_constructed(Tlv). -encode([Tlv]) -> - encode(Tlv); -encode({TlvTag,TlvVal}) when is_list(TlvVal) -> +encode(Tlv) -> + encode(Tlv,erlang). + +encode(Tlv,_) when is_binary(Tlv) -> + Tlv; +encode([Tlv],Method) -> + encode(Tlv,Method); +encode(Tlv, nif) -> + case is_nif_loadable() of + true -> + asn1rt_nif:encode_ber_tlv(Tlv); + false -> + encode_erl(Tlv) + end; +encode(Tlv, _) -> + encode_erl(Tlv). + +encode_erl({TlvTag,TlvVal}) when is_list(TlvVal) -> %% constructed form of value encode_tlv(TlvTag,TlvVal,?CONSTRUCTED); -encode({TlvTag,TlvVal}) -> - encode_tlv(TlvTag,TlvVal,?PRIMITIVE); -encode(Bin) when is_binary(Bin) -> - Bin. +encode_erl({TlvTag,TlvVal}) -> + encode_tlv(TlvTag,TlvVal,?PRIMITIVE). encode_tlv(TlvTag,TlvVal,Form) -> Tag = encode_tlv_tag(TlvTag,Form), @@ -153,7 +169,7 @@ encode_tlv_val(Bin) -> {Bin,size(Bin)}. encode_tlv_list([Tlv|Tlvs],Acc) -> - EncTlv = encode(Tlv), + EncTlv = encode_erl(Tlv), encode_tlv_list(Tlvs,[EncTlv|Acc]); encode_tlv_list([],Acc) -> Bin=list_to_binary(lists:reverse(Acc)), @@ -164,28 +180,36 @@ decode(B) -> %% asn1-1.7 decode(B, nif) -> - case application:get_env(asn1, nif_loadable) of - {ok, true} -> + case is_nif_loadable() of + true -> case asn1rt_nif:decode_ber_tlv(B) of {error, Reason} -> handle_error(Reason, B); Else -> Else end; - {ok, false} -> - decode(B); - undefined -> - case catch code:load_file(asn1rt_nif) of - {module, asn1rt_nif} -> - application:set_env(asn1, nif_loadable, true); - _Else -> - application:set_env(asn1, nif_loadable, false) - end, - decode(B, nif) + false -> + decode(B) end; decode(B,erlang) when is_binary(B) -> decode_primitive(B); decode(Tlv,erlang) -> {Tlv,<<>>}. +%% Have to check this since asn1 is not guaranteed to be available +is_nif_loadable() -> + case application:get_env(asn1, nif_loadable) of + {ok,R} -> + R; + undefined -> + case catch code:load_file(asn1rt_nif) of + {module, asn1rt_nif} -> + application:set_env(asn1, nif_loadable, true), + true; + _Else -> + application:set_env(asn1, nif_loadable, false), + false + end + end. + handle_error([],_)-> exit({error,{asn1,{"memory allocation problem"}}}); handle_error({$1,_},L) -> % error in nif @@ -780,12 +804,14 @@ decode_open_type(Tlv, TagIn, Method) -> end. -decode_open_type_as_binary(Tlv,TagIn)-> +decode_open_type_as_binary(Tlv, TagIn) -> + decode_open_type_as_binary(Tlv, TagIn, erlang). +decode_open_type_as_binary(Tlv,TagIn, Method)-> case match_tags(Tlv,TagIn) of V when is_binary(V) -> V; - [Tlv2] -> encode(Tlv2); - Tlv2 -> encode(Tlv2) + [Tlv2] -> encode(Tlv2, Method); + Tlv2 -> encode(Tlv2, Method) end. %%=============================================================================== diff --git a/lib/asn1/src/asn1rt_nif.erl b/lib/asn1/src/asn1rt_nif.erl index 8580c70e6b..de1fb94816 100644 --- a/lib/asn1/src/asn1rt_nif.erl +++ b/lib/asn1/src/asn1rt_nif.erl @@ -22,7 +22,8 @@ %% Nif interface for asn1 -export([encode_per_complete/1, - decode_ber_tlv/1]). + decode_ber_tlv/1, + encode_ber_tlv/1]). -on_load(load_nif/0). @@ -76,8 +77,11 @@ load_nif() -> Status end. -encode_per_complete(_Binary) -> +encode_per_complete(_TagValueList) -> erlang:nif_error({nif_not_loaded,module,?MODULE,line,?LINE}). decode_ber_tlv(_Binary) -> erlang:nif_error({nif_not_loaded,module,?MODULE,line,?LINE}). + +encode_ber_tlv(_TagValueList) -> + erlang:nif_error({nif_not_loaded,module,?MODULE,line,?LINE}). diff --git a/lib/asn1/test/asn1_bin_v2_particular_SUITE.erl.src b/lib/asn1/test/asn1_bin_v2_particular_SUITE.erl.src index 6e15aa9fdc..4c3c8c7808 100644 --- a/lib/asn1/test/asn1_bin_v2_particular_SUITE.erl.src +++ b/lib/asn1/test/asn1_bin_v2_particular_SUITE.erl.src @@ -1,5 +1,5 @@ -particular() -> [smp, per_performance, ber_performance, ticket7904]. +particular() -> [smp, ticket7904]. smp(suite) -> []; @@ -34,104 +34,186 @@ smp(Config) -> end. per_performance(Config) -> + PrivDir = proplists:get_value(priv_dir, Config), + NifDir = filename:join(PrivDir,"nif"), + ErlDir = filename:join(PrivDir,"erl"), + file:make_dir(NifDir),file:make_dir(ErlDir), ?line Msg = {initiatingMessage, testNBAPsystem:cell_setup_req_msg()}, - ?line ok = testNBAPsystem:compile(Config,per_bin,[optimize]), - NumOfProcs = erlang:system_info(schedulers)*10, - N = 10000, - SmpN = lists:seq(1,round(N/NumOfProcs)), - - asn1_wrapper:encode('NBAP-PDU-Discriptions','NBAP-PDU', Msg), - - PerFun = fun() -> - [asn1_wrapper:encode('NBAP-PDU-Discriptions', - 'NBAP-PDU', - Msg) || _I <- lists:seq(1,N)], - ok + ?line ok = testNBAPsystem:compile([{priv_dir,NifDir}|Config],per_bin, + [optimize]), + ?line ok = testNBAPsystem:compile([{priv_dir,ErlDir}|Config],per_bin, + []), + + Modules = ['NBAP-CommonDataTypes', + 'NBAP-Constants', + 'NBAP-Containers', + 'NBAP-IEs', + 'NBAP-PDU-Contents', + 'NBAP-PDU-Discriptions'], + + + PreNif = fun() -> + code:add_patha(NifDir), + lists:foreach(fun(M) -> + code:purge(M), + code:load_file(M) + end,Modules) + end, + + PreErl = fun() -> + code:add_patha(ErlDir), + lists:foreach(fun(M) -> + code:purge(M), + code:load_file(M) + end,Modules) end, - PerSMPFun = - fun() -> - pforeach(fun(_) -> - [asn1_wrapper:encode('NBAP-PDU-Discriptions', - 'NBAP-PDU', - Msg) || _I <- SmpN] - end,lists:seq(1,NumOfProcs)) - end, - - ?line {TimeN,ok} = timer:tc(PerFun), - ?line {TimeNS,ok} = timer:tc(PerSMPFun), - - ?line ok = testNBAPsystem:compile(Config,per_bin,[]), - - ?line {TimeE,ok} = timer:tc(PerFun), - ?line {TimeES,ok} = timer:tc(PerSMPFun), - - ct:log("Seq:<br/>" - "Nif : ~p (~.2f%)<br/>" - "Erlang: ~p (~.2f%)<br/>" - "Parallel:<br/>" - "Nif : ~p (~.2f%)<br/>" - "Erlang: ~p (~.2f%)<br/>", - [TimeN,TimeN/TimeN*100, - TimeE,TimeE/TimeN*100, - TimeNS,TimeNS/TimeNS*100, - TimeES,TimeES/TimeNS*100]), - - {comment, lists:flatten(io_lib:format("Nifs are ~.2f% faster than erlang!", - [faster(TimeN+TimeNS, - TimeE+TimeES)]))}. + Func = fun() -> + element(1,timer:tc( + asn1_wrapper,encode,['NBAP-PDU-Discriptions', + 'NBAP-PDU', + Msg])) + end, + + nif_vs_erlang_performance({{{PreNif,Func},{PreErl,Func}},100000,32}). ber_performance(Config) -> ?line Msg = {initiatingMessage, testNBAPsystem:cell_setup_req_msg()}, ?line ok = testNBAPsystem:compile(Config,ber_bin,[optimize,nif]), - NumOfProcs = erlang:system_info(schedulers)*10, - N = 10000, - SmpN = lists:seq(1,round(N/NumOfProcs)), - {ok,B} = asn1_wrapper:encode('NBAP-PDU-Discriptions','NBAP-PDU', Msg), BerFun = fun() -> - [asn1_wrapper:decode( + {ok,B} = asn1_wrapper:encode('NBAP-PDU-Discriptions', + 'NBAP-PDU', Msg), + asn1_wrapper:decode( 'NBAP-PDU-Discriptions', 'NBAP-PDU', - B) || _I <- lists:seq(1,N)], - ok + B) end, - BerSMPFun = - fun() -> - pforeach(fun(_) -> - [asn1_wrapper:decode( - 'NBAP-PDU-Discriptions', - 'NBAP-PDU', - B) || _I <- SmpN] - end,lists:seq(1,NumOfProcs)) - end, - - ?line {TimeN,ok} = timer:tc(BerFun), - ?line {TimeNS,ok} = timer:tc(BerSMPFun), + nif_vs_erlang_performance({BerFun,100000,32}). - ?line ok = testNBAPsystem:compile(Config,ber_bin,[optimize]), +cert_pem_performance(Config) when is_list(Config) -> + cert_pem_performance({100000, 32}); +cert_pem_performance({N,S}) -> + nif_vs_erlang_performance({fun cert_pem/0,N,S}). - ?line {TimeE,ok} = timer:tc(BerFun), - ?line {TimeES,ok} = timer:tc(BerSMPFun), +dsa_pem_performance(Config) when is_list(Config) -> + cert_pem_performance({100000, 32}); +dsa_pem_performance({N,S}) -> + nif_vs_erlang_performance({fun dsa_pem/0,N,S}). + + +nif_vs_erlang_performance({{TC1,TC2},N,Sched}) -> + random:seed({123,456,789}), + io:format("Running a ~p sample with ~p max procs...~n~n",[N,Sched]), + + {True,False} = exec(TC1,TC2,Sched,N+1), + + io:format("~ndone!~n"), + + io:format("~n"),TStats = print_stats(strip(True,N div 20)), + io:format("~n"),FStats = print_stats(strip(False,N div 20)), + Str = io_lib:format("~nNifs are ~.3f% faster than erlang!~n", + [(element(2,FStats) - element(2,TStats)) / + element(2,FStats) * 100]), + io:format(Str), + {comment, lists:flatten(Str)}; +nif_vs_erlang_performance({T,N,Sched}) -> + PTC1 = fun() -> + application:set_env(asn1, nif_loadable, true) + end, + PTC2 = fun() -> + application:set_env(asn1, nif_loadable, false) + end, + TC = fun() -> + element(1,timer:tc(T)) + end, + nif_vs_erlang_performance({{{PTC1,TC},{PTC2,TC}},N,Sched}). + - ct:log("Seq:<br/>" - "Nif : ~p (~.2f%)<br/>" - "Erlang: ~p (~.2f%)<br/>" - "Parallel:<br/>" - "Nif : ~p (~.2f%)<br/>" - "Erlang: ~p (~.2f%)<br/>", - [TimeN,TimeN/TimeN*100, - TimeE,TimeE/TimeN*100, - TimeNS,TimeNS/TimeNS*100, - TimeES,TimeES/TimeNS*100]), +print_stats(Data) -> + Length = length(Data), + Mean = lists:sum(Data) / Length, + Variance = lists:foldl(fun(N,Acc) -> math:pow(N - Mean, 2)+Acc end, 0, Data), + StdDev = math:sqrt(Variance / Length), + Median = lists:nth(round(Length/2),Data), + Min = lists:min(Data), + Max = lists:max(Data), + if Length < 20 -> + io:format("Data: ~w~n",[Data]); + true -> + ok + end, + io:format("Length: ~p~nMean: ~p~nStdDev: ~p~nMedian: ~p~nMin: ~p~nMax: ~p~n", + [Length,Mean,StdDev,Median,Min,Max]), + {Length,Mean,StdDev,Median,Min,Max}. + +collect(Acc) -> + receive + {Tag,Val} -> + Prev = proplists:get_value(Tag,Acc,[]), + collect(lists:keystore(Tag,1,Acc,{Tag,[Val|Prev]})) + after 100 -> + Acc + end. - {comment, lists:flatten(io_lib:format("Nifs are ~.2f% faster than erlang!", - [faster(TimeN+TimeNS, - TimeE+TimeES)]))}. +exec(One,Two,Max,N) -> + exec(One,Two,Max,N,{[],[]}). +exec(_,_,_,1,{D1,D2}) -> + {lists:flatten(D1),lists:flatten(D2)}; +exec({PreOne,One} = O,{PreTwo,Two} = T,MaxProcs, N, {D1,D2}) -> + Num = random:uniform(round(N/2)), + if Num rem 3 == 0 -> + timer:sleep(Num rem 1000); + true -> + ok + end, + Procs = random:uniform(MaxProcs), + io:format("\tBatch: ~p items in ~p processes, ~p left~n",[Num,Procs,N-Num]), + if Num rem 2 == 1 -> + erlang:garbage_collect(), + PreOne(), + MoreOne = pexec(One, Num, Procs, []), + erlang:garbage_collect(), + PreTwo(), + MoreTwo = pexec(Two, Num, Procs, []); + true -> + erlang:garbage_collect(), + PreTwo(), + MoreTwo = pexec(Two, Num, Procs, []), + erlang:garbage_collect(), + PreOne(), + MoreOne = pexec(One, Num, Procs, []) + end, + exec(O,T,MaxProcs,N-Num,{[MoreOne|D1], + [MoreTwo|D2]}). + +pexec(_Fun, _, 0, []) -> + []; +pexec(Fun, _, 0, [{Ref,Pid}|Rest]) -> + receive + {data,D} -> + [D|pexec(Fun,0,0,[{Ref,Pid}|Rest])]; + {'DOWN', Ref, process, Pid, normal} -> + pexec(Fun, 0,0,Rest) + end; +pexec(Fun, 0, 1, AccProcs) -> + pexec(Fun, 0, 0, AccProcs); +pexec(Fun, N, 1, AccProcs) -> + [Fun()|pexec(Fun, N - 1, 1, AccProcs)]; +pexec(Fun, N, Procs, AccProcs) -> + S = self(), + Pid = spawn(fun() -> + S ! {data,pexec(Fun,N,1,[])} + end), + Ref = erlang:monitor(process, Pid), + pexec(Fun, N, Procs - 1, [{Ref,Pid}|AccProcs]). +strip(Data,Num) -> + {_,R} = lists:split(Num,lists:sort(Data)), + element(2,lists:split(Num,lists:reverse(R))). faster(A,B) -> (B - A)/B * 100. @@ -189,3 +271,21 @@ ticket7904(Config) -> ?line {ok,_} = 'RANAPextract1':encode('InitiatingMessage', Val1), asn1rt:unload_driver(), ?line {ok,_} = 'RANAPextract1':encode('InitiatingMessage', Val1). + +cert_pem() -> + 'OTP-PUB-KEY':decode('Certificate',<<48,130,3,184,48,130,3,33,160,3,2,1,2,2,1,1,48,13,6,9,42,134,72,134,247,13,1,1,5,5,0,48,129,131,49,14,48,12,6,3,85,4,3,19,5,111,116,112,67,65,49,19,48,17,6,3,85,4,11,19,10,69,114,108,97,110,103,32,79,84,80,49,20,48,18,6,3,85,4,10,19,11,69,114,105,99,115,115,111,110,32,65,66,49,11,48,9,6,3,85,4,6,19,2,83,69,49,18,48,16,6,3,85,4,7,19,9,83,116,111,99,107,104,111,108,109,49,37,48,35,6,9,42,134,72,134,247,13,1,9,1,22,22,112,101,116,101,114,64,101,114,105,120,46,101,114,105,99,115,115,111,110,46,115,101,48,30,23,13,48,56,48,49,48,57,48,56,50,57,51,48,90,23,13,49,55,49,49,49,55,48,56,50,57,51,48,90,48,129,132,49,15,48,13,6,3,85,4,3,19,6,99,108,105,101,110,116,49,19,48,17,6,3,85,4,11,19,10,69,114,108,97,110,103,32,79,84,80,49,20,48,18,6,3,85,4,10,19,11,69,114,105,99,115,115,111,110,32,65,66,49,11,48,9,6,3,85,4,6,19,2,83,69,49,18,48,16,6,3,85,4,7,19,9,83,116,111,99,107,104,111,108,109,49,37,48,35,6,9,42,134,72,134,247,13,1,9,1,22,22,112,101,116,101,114,64,101,114,105,120,46,101,114,105,99,115,115,111,110,46,115,101,48,129,159,48,13,6,9,42,134,72,134,247,13,1,1,1,5,0,3,129,141,0,48,129,137,2,129,129,0,245,56,68,254,220,239,193,190,63,221,182,60,67,77,121,163,214,136,137,183,139,8,166,30,100,27,45,17,126,58,15,173,151,218,75,224,148,14,22,164,10,100,186,183,104,175,197,97,96,182,146,150,106,129,140,100,194,106,90,62,133,233,155,46,155,33,101,220,83,193,182,232,240,99,253,249,114,8,159,172,143,77,179,132,229,205,29,110,185,233,224,52,25,149,249,100,80,229,199,125,23,106,146,233,159,26,13,8,161,206,221,43,240,149,42,45,194,190,85,6,235,152,220,219,160,32,144,67,2,3,1,0,1,163,130,1,55,48,130,1,51,48,9,6,3,85,29,19,4,2,48,0,48,11,6,3,85,29,15,4,4,3,2,5,224,48,29,6,3,85,29,14,4,22,4,20,26,59,44,5,72,211,158,214,23,34,30,241,125,27,123,115,93,163,231,120,48,129,179,6,3,85,29,35,4,129,171,48,129,168,128,20,6,171,128,52,58,164,184,118,178,189,157,46,40,229,109,145,222,125,1,155,161,129,140,164,129,137,48,129,134,49,17,48,15,6,3,85,4,3,19,8,101,114,108,97,110,103,67,65,49,19,48,17,6,3,85,4,11,19,10,69,114,108,97,110,103,32,79,84,80,49,20,48,18,6,3,85,4,10,19,11,69,114,105,99,115,115,111,110,32,65,66,49,18,48,16,6,3,85,4,7,19,9,83,116,111,99,107,104,111,108,109,49,11,48,9,6,3,85,4,6,19,2,83,69,49,37,48,35,6,9,42,134,72,134,247,13,1,9,1,22,22,112,101,116,101,114,64,101,114,105,120,46,101,114,105,99,115,115,111,110,46,115,101,130,1,1,48,33,6,3,85,29,17,4,26,48,24,129,22,112,101,116,101,114,64,101,114,105,120,46,101,114,105,99,115,115,111,110,46,115,101,48,33,6,3,85,29,18,4,26,48,24,129,22,112,101,116,101,114,64,101,114,105,120,46,101,114,105,99,115,115,111,110,46,115,101,48,13,6,9,42,134,72,134,247,13,1,1,5,5,0,3,129,129,0,93,11,112,227,121,15,121,179,247,135,110,216,17,197,84,18,149,166,147,142,190,178,0,209,190,0,142,233,144,100,194,205,220,182,73,204,108,42,95,23,48,63,4,120,239,42,194,25,184,35,117,107,96,229,18,45,76,122,125,40,171,210,132,50,146,178,160,55,17,35,255,208,114,30,47,55,185,154,155,165,204,180,14,143,20,234,6,234,201,225,72,235,5,87,61,255,250,23,217,1,144,246,98,221,223,102,49,168,177,13,70,241,26,27,254,251,217,14,244,18,242,197,151,50,186,214,15,42>>). + +dsa_pem() -> + 'OTP-PUB-KEY':decode('DSAPrivateKey',<<48,130,1,187,2,1,0,2,129,129,0,183,179,230,217,37,99,144,157,21,228,204,162,207,61,246,144,58,139,139,184,184,43,108,206,0,115,173,208,100,233,201,121,21,90,179,119,53,140,25,52,34,202,121,211,164,107,43,56,68,162,159,51,244,232,138,126,164,109,121,89,237,142,57,28,32,188,44,67,253,111,121,104,40,141,211,255,140,118,37,234,150,201,155,160,16,17,51,59,26,249,41,129,16,211,119,128,95,254,182,235,132,0,92,206,93,77,106,217,201,132,203,4,75,201,246,204,216,162,1,84,79,211,10,21,152,195,103,145,2,21,0,213,30,184,86,247,16,247,69,192,241,35,138,84,57,140,3,71,65,206,233,2,129,129,0,148,179,24,63,74,91,128,25,96,29,5,78,223,246,175,0,121,86,54,178,42,231,98,241,147,180,157,60,149,160,50,243,227,76,175,89,234,203,252,242,76,108,9,204,157,182,59,206,227,127,99,215,42,156,194,78,116,25,7,62,243,169,45,5,101,179,247,127,199,144,135,103,23,42,154,125,231,248,154,101,175,155,101,42,232,41,80,41,47,128,208,11,31,106,63,12,202,207,135,80,200,136,250,171,31,118,52,91,200,138,112,111,179,23,214,123,21,118,194,179,0,185,217,52,197,182,236,13,2,129,128,124,66,0,111,121,139,142,209,95,136,95,237,177,150,248,252,49,135,117,100,155,232,138,244,132,89,40,5,70,125,202,96,78,239,76,37,125,149,82,64,107,54,227,73,25,180,227,41,0,234,73,47,80,242,242,129,250,61,68,62,39,38,156,193,146,40,241,247,106,215,223,202,194,110,130,62,186,90,18,28,196,174,99,47,193,61,130,100,150,25,248,115,164,231,153,99,46,69,66,139,33,187,51,49,35,219,234,29,44,172,166,247,42,16,177,187,9,162,81,243,33,26,100,46,78,57,203,135,2,20,89,128,159,14,187,249,182,172,15,88,162,110,211,71,179,209,29,125,217,38>>), + 'OTP-PUB-KEY':decode('SubjectPublicKeyInfo',<<48,130,1,183,48,130,1,44,6,7,42,134,72,206,56,4,1,48,130,1,31,2,129,129,0,183,179,230,217,37,99,144,157,21,228,204,162,207,61,246,144,58,139,139,184,184,43,108,206,0,115,173,208,100,233,201,121,21,90,179,119,53,140,25,52,34,202,121,211,164,107,43,56,68,162,159,51,244,232,138,126,164,109,121,89,237,142,57,28,32,188,44,67,253,111,121,104,40,141,211,255,140,118,37,234,150,201,155,160,16,17,51,59,26,249,41,129,16,211,119,128,95,254,182,235,132,0,92,206,93,77,106,217,201,132,203,4,75,201,246,204,216,162,1,84,79,211,10,21,152,195,103,145,2,21,0,213,30,184,86,247,16,247,69,192,241,35,138,84,57,140,3,71,65,206,233,2,129,129,0,148,179,24,63,74,91,128,25,96,29,5,78,223,246,175,0,121,86,54,178,42,231,98,241,147,180,157,60,149,160,50,243,227,76,175,89,234,203,252,242,76,108,9,204,157,182,59,206,227,127,99,215,42,156,194,78,116,25,7,62,243,169,45,5,101,179,247,127,199,144,135,103,23,42,154,125,231,248,154,101,175,155,101,42,232,41,80,41,47,128,208,11,31,106,63,12,202,207,135,80,200,136,250,171,31,118,52,91,200,138,112,111,179,23,214,123,21,118,194,179,0,185,217,52,197,182,236,13,3,129,132,0,2,129,128,124,66,0,111,121,139,142,209,95,136,95,237,177,150,248,252,49,135,117,100,155,232,138,244,132,89,40,5,70,125,202,96,78,239,76,37,125,149,82,64,107,54,227,73,25,180,227,41,0,234,73,47,80,242,242,129,250,61,68,62,39,38,156,193,146,40,241,247,106,215,223,202,194,110,130,62,186,90,18,28,196,174,99,47,193,61,130,100,150,25,248,115,164,231,153,99,46,69,66,139,33,187,51,49,35,219,234,29,44,172,166,247,42,16,177,187,9,162,81,243,33,26,100,46,78,57,203,135>>), + 'OTP-PUB-KEY':decode('DSAParams',<<48,130,1,31,2,129,129,0,183,179,230,217,37,99,144,157,21,228,204,162,207,61,246,144,58,139,139,184,184,43,108,206,0,115,173,208,100,233,201,121,21,90,179,119,53,140,25,52,34,202,121,211,164,107,43,56,68,162,159,51,244,232,138,126,164,109,121,89,237,142,57,28,32,188,44,67,253,111,121,104,40,141,211,255,140,118,37,234,150,201,155,160,16,17,51,59,26,249,41,129,16,211,119,128,95,254,182,235,132,0,92,206,93,77,106,217,201,132,203,4,75,201,246,204,216,162,1,84,79,211,10,21,152,195,103,145,2,21,0,213,30,184,86,247,16,247,69,192,241,35,138,84,57,140,3,71,65,206,233,2,129,129,0,148,179,24,63,74,91,128,25,96,29,5,78,223,246,175,0,121,86,54,178,42,231,98,241,147,180,157,60,149,160,50,243,227,76,175,89,234,203,252,242,76,108,9,204,157,182,59,206,227,127,99,215,42,156,194,78,116,25,7,62,243,169,45,5,101,179,247,127,199,144,135,103,23,42,154,125,231,248,154,101,175,155,101,42,232,41,80,41,47,128,208,11,31,106,63,12,202,207,135,80,200,136,250,171,31,118,52,91,200,138,112,111,179,23,214,123,21,118,194,179,0,185,217,52,197,182,236,13>>), + 'OTP-PUB-KEY':decode('DSAPublicKey',<<2,129,128,124,66,0,111,121,139,142,209,95,136,95,237,177,150,248,252,49,135,117,100,155,232,138,244,132,89,40,5,70,125,202,96,78,239,76,37,125,149,82,64,107,54,227,73,25,180,227,41,0,234,73,47,80,242,242,129,250,61,68,62,39,38,156,193,146,40,241,247,106,215,223,202,194,110,130,62,186,90,18,28,196,174,99,47,193,61,130,100,150,25,248,115,164,231,153,99,46,69,66,139,33,187,51,49,35,219,234,29,44,172,166,247,42,16,177,187,9,162,81,243,33,26,100,46,78,57,203,135>>), + 'OTP-PUB-KEY':encode('DSAParams',{params,{'Dss-Parms',129000451850199666185842362389296595317127259539517666765336291347244303954511451744518587442120964433734460998523119938005801396466878889993179871123036311260456172022864663021425348874648247531097042575063545128239655736096045972718934778583429973433661785691086624069991876932064334822608460064613803976593,1216700114794736143432235288305776850295620488937,104420402274523493329542694749036577763086597934731674202966304958550599470165597750883637440049774107540742087494301536297571301945349213110548764383811017178451900599240379681904765817950545426764751538502808499880604633364255316249231153053427235538288687666086821781456733226598288985591031656134573747213}}), + 'OTP-PUB-KEY':encode( + 'SubjectPublicKeyInfo', + {'SubjectPublicKeyInfo', + {'AlgorithmIdentifier', + {1,2,840,10040,4,1}, + <<48,130,1,31,2,129,129,0,183,179,230,217,37,99,144,157,21,228,204,162,207,61,246,144,58,139,139,184,184,43,108,206,0,115,173,208,100,233,201,121,21,90,179,119,53,140,25,52,34,202,121,211,164,107,43,56,68,162,159,51,244,232,138,126,164,109,121,89,237,142,57,28,32,188,44,67,253,111,121,104,40,141,211,255,140,118,37,234,150,201,155,160,16,17,51,59,26,249,41,129,16,211,119,128,95,254,182,235,132,0,92,206,93,77,106,217,201,132,203,4,75,201,246,204,216,162,1,84,79,211,10,21,152,195,103,145,2,21,0,213,30,184,86,247,16,247,69,192,241,35,138,84,57,140,3,71,65,206,233,2,129,129,0,148,179,24,63,74,91,128,25,96,29,5,78,223,246,175,0,121,86,54,178,42,231,98,241,147,180,157,60,149,160,50,243,227,76,175,89,234,203,252,242,76,108,9,204,157,182,59,206,227,127,99,215,42,156,194,78,116,25,7,62,243,169,45,5,101,179,247,127,199,144,135,103,23,42,154,125,231,248,154,101,175,155,101,42,232,41,80,41,47,128,208,11,31,106,63,12,202,207,135,80,200,136,250,171,31,118,52,91,200,138,112,111,179,23,214,123,21,118,194,179,0,185,217,52,197,182,236,13>>}, + {0, + <<2,129,128,124,66,0,111,121,139,142,209,95,136,95,237,177,150,248,252,49,135,117,100,155,232,138,244,132,89,40,5,70,125,202,96,78,239,76,37,125,149,82,64,107,54,227,73,25,180,227,41,0,234,73,47,80,242,242,129,250,61,68,62,39,38,156,193,146,40,241,247,106,215,223,202,194,110,130,62,186,90,18,28,196,174,99,47,193,61,130,100,150,25,248,115,164,231,153,99,46,69,66,139,33,187,51,49,35,219,234,29,44,172,166,247,42,16,177,187,9,162,81,243,33,26,100,46,78,57,203,135>>}}). |