From 4a736966eba5398a22697db6ca67e1e3dd3cd0f2 Mon Sep 17 00:00:00 2001 From: Lukas Larsson Date: Thu, 10 Dec 2015 10:58:33 +0100 Subject: erts: Add enif_cpu/now_time and enif_make_unique_integer --- erts/doc/src/erl_nif.xml | 201 ++++++++++++++++---------- erts/emulator/beam/erl_bif_unique.c | 20 +-- erts/emulator/beam/erl_bif_unique.h | 12 +- erts/emulator/beam/erl_nif.c | 45 ++++++ erts/emulator/beam/erl_nif.h | 5 + erts/emulator/beam/erl_nif_api_funcs.h | 6 + erts/emulator/beam/erl_trace.c | 5 +- erts/emulator/test/nif_SUITE.erl | 62 +++++++- erts/emulator/test/nif_SUITE_data/nif_SUITE.c | 36 ++++- 9 files changed, 297 insertions(+), 95 deletions(-) diff --git a/erts/doc/src/erl_nif.xml b/erts/doc/src/erl_nif.xml index be0e406b9c..e62f5792a5 100644 --- a/erts/doc/src/erl_nif.xml +++ b/erts/doc/src/erl_nif.xml @@ -591,6 +591,21 @@ typedef enum { + ErlNifUniqueInteger + +

An enumeration of the properties that can be requested from + + enif_unique_integer.

+ + ERL_NIF_UNIQUE_POSITIVE +

A positive integer

+ ERL_NIF_UNIQUE_MONOTONIC +

A + strictly + monotonically increasing integer corresponding to creation time

+
+
+ @@ -689,7 +704,49 @@ typedef enum { a number of repeated NIF-calls without the need to create threads. See also the warning text at the beginning of this document.

+ + + + + ErlNifTimeenif_convert_time_unit(ErlNifTime val, ErlNifTimeUnit from, ErlNifTimeUnit to) + Convert time unit of a time value + + +

Arguments:

+ + val + Value to convert time unit for. + from + Time unit of val. + to + Time unit of returned value. + +

Converts the val value of time unit from to + the corresponding value of time unit to. The result is + rounded using the floor function.

+

Returns ERL_NIF_TIME_ERROR if called with an invalid + time unit argument.

+

See also:

+ + ErlNifTime + ErlNifTimeUnit + +
+ + + ERL_NIF_TERMenif_cpu_time(ErlNifEnv *) + + +

Returns the CPU time in the same format as erlang:timestamp(). + The CPU time is the time the current logical cpu has spent executing since + some arbitrary point in the past. + If the OS does not support fetching of this value enif_cpu_time + invokes enif_make_badarg. +

+
+
+ intenif_equal_tids(ErlNifTid tid1, ErlNifTid tid2)

Same as erl_drv_equal_tids. @@ -1195,6 +1252,24 @@ typedef enum { Create an unsigned integer term

Create an integer term from an unsigned 64-bit integer.

+ + ERL_NIF_TERMenif_make_unique_integer(ErlNifEnv *env, ErlNifUniqueInteger properties) + + +

Returns a unique integer with the same properties as given by erlang:unique_integer/1.

+

env is the environment to create the integer in.

+

+ ERL_NIF_UNIQUE_POSITIVE and ERL_NIF_UNIQUE_MONOTONIC can + be passed as the second argument to change the properties of the + integer returned. It is possible to combine them by or:ing the + two values together. +

+

See also:

+ + ErlNifUniqueInteger + +
+
ERL_NIF_TERMenif_make_ulong(ErlNifEnv* env, unsigned long i) Create an integer term from an unsigned long int

Create an integer term from an unsigned long int.

@@ -1265,6 +1340,34 @@ enif_map_iterator_destroy(env, &iter); or false if the iterator is positioned at the head (before the first entry).

+ + + ErlNifTimeenif_monotonic_time(ErlNifTimeUnit time_unit) + Get Erlang Monotonic Time + + +

Arguments:

+ + time_unit + Time unit of returned value. + +

+ Returns + Erlang + monotonic time. Note that it is not uncommon with + negative values. +

+

Returns ERL_NIF_TIME_ERROR if called with an invalid + time unit argument, or if called from a thread that is not a + scheduler thread.

+

See also:

+ + ErlNifTime + ErlNifTimeUnit + +
+
+ ErlNifMutex *enif_mutex_create(char *name)

Same as erl_drv_mutex_create. @@ -1290,6 +1393,11 @@ enif_map_iterator_destroy(env, &iter);

Same as erl_drv_mutex_unlock.

+ ERL_NIF_TERMenif_now_time(ErlNifEnv *env) + +

Retuns an erlang:now() timestamp. + The enif_now_time function is deprecated.

+
ErlNifResourceType *enif_open_resource_type(ErlNifEnv* env, const char* module_str, const char* name, ErlNifResourceDtor* dtor, ErlNifResourceFlags flags, ErlNifResourceFlags* tried) @@ -1496,54 +1604,6 @@ enif_map_iterator_destroy(env, &iter);

Same as erl_drv_thread_self.

- intenif_tsd_key_create(char *name, ErlNifTSDKey *key) - -

Same as erl_drv_tsd_key_create. -

-
- voidenif_tsd_key_destroy(ErlNifTSDKey key) - -

Same as erl_drv_tsd_key_destroy. -

-
- void *enif_tsd_get(ErlNifTSDKey key) - -

Same as erl_drv_tsd_get. -

-
- voidenif_tsd_set(ErlNifTSDKey key, void *data) - -

Same as erl_drv_tsd_set. -

-
- - - - ErlNifTimeenif_monotonic_time(ErlNifTimeUnit time_unit) - Get Erlang Monotonic Time - - -

Arguments:

- - time_unit - Time unit of returned value. - -

- Returns - Erlang - monotonic time. Note that it is not uncommon with - negative values. -

-

Returns ERL_NIF_TIME_ERROR if called with an invalid - time unit argument, or if called from a thread that is not a - scheduler thread.

-

See also:

- - ErlNifTime - ErlNifTimeUnit - -
-
ErlNifTimeenif_time_offset(ErlNifTimeUnit time_unit) @@ -1571,33 +1631,26 @@ enif_map_iterator_destroy(env, &iter); - - ErlNifTimeenif_convert_time_unit(ErlNifTime val, ErlNifTimeUnit from, ErlNifTimeUnit to) - Convert time unit of a time value - - -

Arguments:

- - val - Value to convert time unit for. - from - Time unit of val. - to - Time unit of returned value. - -

Converts the val value of time unit from to - the corresponding value of time unit to. The result is - rounded using the floor function.

-

Returns ERL_NIF_TIME_ERROR if called with an invalid - time unit argument.

-

See also:

- - ErlNifTime - ErlNifTimeUnit - -
+ intenif_tsd_key_create(char *name, ErlNifTSDKey *key) + +

Same as erl_drv_tsd_key_create. +

+
+ voidenif_tsd_key_destroy(ErlNifTSDKey key) + +

Same as erl_drv_tsd_key_destroy. +

+
+ void *enif_tsd_get(ErlNifTSDKey key) + +

Same as erl_drv_tsd_get. +

+
+ voidenif_tsd_set(ErlNifTSDKey key, void *data) + +

Same as erl_drv_tsd_set. +

-
SEE ALSO diff --git a/erts/emulator/beam/erl_bif_unique.c b/erts/emulator/beam/erl_bif_unique.c index c4a39b8897..c9c8561f64 100644 --- a/erts/emulator/beam/erl_bif_unique.c +++ b/erts/emulator/beam/erl_bif_unique.c @@ -266,17 +266,19 @@ static ERTS_INLINE Eterm unique_integer_bif(Process *c_p, int positive) } Uint -erts_raw_unique_integer_heap_size(Uint64 val[ERTS_UNIQUE_INT_RAW_VALUES]) +erts_raw_unique_integer_heap_size(Uint64 val[ERTS_UNIQUE_INT_RAW_VALUES], + int positive) { Uint sz; - bld_unique_integer_term(NULL, &sz, val[0], val[1], 0); + bld_unique_integer_term(NULL, &sz, val[0], val[1], positive); return sz; } Eterm -erts_raw_make_unique_integer(Eterm **hpp, Uint64 val[ERTS_UNIQUE_INT_RAW_VALUES]) +erts_raw_make_unique_integer(Eterm **hpp, Uint64 val[ERTS_UNIQUE_INT_RAW_VALUES], + int positive) { - return bld_unique_integer_term(hpp, NULL, val[0], val[1], 0); + return bld_unique_integer_term(hpp, NULL, val[0], val[1], positive); } void @@ -426,16 +428,16 @@ erts_raw_get_unique_monotonic_integer(void) } Uint -erts_raw_unique_monotonic_integer_heap_size(Sint64 raw) +erts_raw_unique_monotonic_integer_heap_size(Sint64 raw, int positive) { - return get_unique_monotonic_integer_heap_size(raw, 0); + return get_unique_monotonic_integer_heap_size(raw, positive); } Eterm -erts_raw_make_unique_monotonic_integer_value(Eterm **hpp, Sint64 raw) +erts_raw_make_unique_monotonic_integer_value(Eterm **hpp, Sint64 raw, int positive) { - Uint hsz = get_unique_monotonic_integer_heap_size(raw, 0); - Eterm res = make_unique_monotonic_integer_value(*hpp, hsz, raw, 0); + Uint hsz = get_unique_monotonic_integer_heap_size(raw, positive); + Eterm res = make_unique_monotonic_integer_value(*hpp, hsz, raw, positive); *hpp += hsz; return res; } diff --git a/erts/emulator/beam/erl_bif_unique.h b/erts/emulator/beam/erl_bif_unique.h index 37d5d91c39..94fd6163f2 100644 --- a/erts/emulator/beam/erl_bif_unique.h +++ b/erts/emulator/beam/erl_bif_unique.h @@ -41,8 +41,9 @@ void erts_make_ref_in_array(Uint32 ref[ERTS_MAX_REF_NUMBERS]); * not necessarily correspond to the end result. */ Sint64 erts_raw_get_unique_monotonic_integer(void); -Uint erts_raw_unique_monotonic_integer_heap_size(Sint64 raw); -Eterm erts_raw_make_unique_monotonic_integer_value(Eterm **hpp, Sint64 raw); +Uint erts_raw_unique_monotonic_integer_heap_size(Sint64 raw, int positive); +Eterm erts_raw_make_unique_monotonic_integer_value(Eterm **hpp, Sint64 raw, + int positive); Sint64 erts_get_min_unique_monotonic_integer(void); @@ -53,8 +54,11 @@ Eterm erts_debug_get_unique_monotonic_integer_state(Process *c_p); #define ERTS_UNIQUE_INT_RAW_VALUES 2 #define ERTS_MAX_UNIQUE_INT_HEAP_SIZE ERTS_UINT64_ARRAY_TO_BIG_MAX_HEAP_SZ(2) -Uint erts_raw_unique_integer_heap_size(Uint64 val[ERTS_UNIQUE_INT_RAW_VALUES]); -Eterm erts_raw_make_unique_integer(Eterm **hpp, Uint64 val[ERTS_UNIQUE_INT_RAW_VALUES]); +Uint erts_raw_unique_integer_heap_size(Uint64 val[ERTS_UNIQUE_INT_RAW_VALUES], + int positive); +Eterm erts_raw_make_unique_integer(Eterm **hpp, + Uint64 val[ERTS_UNIQUE_INT_RAW_VALUES], + int postive); void erts_raw_get_unique_integer(Uint64 val[ERTS_UNIQUE_INT_RAW_VALUES]); Sint64 erts_get_min_unique_integer(void); diff --git a/erts/emulator/beam/erl_nif.c b/erts/emulator/beam/erl_nif.c index 8580bc2689..703c96777a 100644 --- a/erts/emulator/beam/erl_nif.c +++ b/erts/emulator/beam/erl_nif.c @@ -1158,6 +1158,51 @@ int enif_make_reverse_list(ErlNifEnv* env, ERL_NIF_TERM term, ERL_NIF_TERM *list return 1; } +ERL_NIF_TERM +enif_now_time(ErlNifEnv *env) +{ + Uint mega, sec, micro; + Eterm *hp; + get_now(&mega, &sec, µ); + hp = alloc_heap(env, 4); + return TUPLE3(hp, make_small(mega), make_small(sec), make_small(micro)); +} + +ERL_NIF_TERM +enif_cpu_time(ErlNifEnv *env) +{ +#ifdef HAVE_ERTS_NOW_CPU + Uint mega, sec, micro; + Eterm *hp; + erts_get_now_cpu(&mega, &sec, µ); + hp = alloc_heap(env, 4); + return TUPLE3(hp, make_small(mega), make_small(sec), make_small(micro)); +#else + return enif_make_badarg(env); +#endif +} + +ERL_NIF_TERM +enif_make_unique_integer(ErlNifEnv *env, ErlNifUniqueInteger properties) +{ + int monotonic = properties & ERL_NIF_UNIQUE_MONOTONIC; + int positive = properties & ERL_NIF_UNIQUE_POSITIVE; + Eterm *hp; + Uint hsz; + + if (monotonic) { + Sint64 raw_unique = erts_raw_get_unique_monotonic_integer(); + hsz = erts_raw_unique_monotonic_integer_heap_size(raw_unique, positive); + hp = alloc_heap(env, hsz); + return erts_raw_make_unique_monotonic_integer_value(&hp, raw_unique, positive); + } else { + Uint64 raw_unique[ERTS_UNIQUE_INT_RAW_VALUES]; + erts_raw_get_unique_integer(raw_unique); + hsz = erts_raw_unique_integer_heap_size(raw_unique, positive); + hp = alloc_heap(env, hsz); + return erts_raw_make_unique_integer(&hp, raw_unique, positive); + } +} ErlNifMutex* enif_mutex_create(char *name) { return erl_drv_mutex_create(name); } void enif_mutex_destroy(ErlNifMutex *mtx) { erl_drv_mutex_destroy(mtx); } diff --git a/erts/emulator/beam/erl_nif.h b/erts/emulator/beam/erl_nif.h index c9c8b1d0af..959fcb5412 100644 --- a/erts/emulator/beam/erl_nif.h +++ b/erts/emulator/beam/erl_nif.h @@ -197,6 +197,11 @@ typedef enum { ERL_NIF_MAP_ITERATOR_TAIL = ERL_NIF_MAP_ITERATOR_LAST } ErlNifMapIteratorEntry; +typedef enum { + ERL_NIF_UNIQUE_POSITIVE = (1 << 0), + ERL_NIF_UNIQUE_MONOTONIC = (1 << 1) +} ErlNifUniqueInteger; + #if (defined(__WIN32__) || defined(_WIN32) || defined(_WIN32_)) # define ERL_NIF_API_FUNC_DECL(RET_TYPE, NAME, ARGS) RET_TYPE (*NAME) ARGS typedef struct { diff --git a/erts/emulator/beam/erl_nif_api_funcs.h b/erts/emulator/beam/erl_nif_api_funcs.h index 1448a508a2..3fe60e3df8 100644 --- a/erts/emulator/beam/erl_nif_api_funcs.h +++ b/erts/emulator/beam/erl_nif_api_funcs.h @@ -163,6 +163,9 @@ ERL_NIF_API_FUNC_DECL(int,enif_getenv,(const char* key, char* value, size_t* val ERL_NIF_API_FUNC_DECL(ErlNifTime, enif_monotonic_time, (ErlNifTimeUnit)); ERL_NIF_API_FUNC_DECL(ErlNifTime, enif_time_offset, (ErlNifTimeUnit)); ERL_NIF_API_FUNC_DECL(ErlNifTime, enif_convert_time_unit, (ErlNifTime, ErlNifTimeUnit, ErlNifTimeUnit)); +ERL_NIF_API_FUNC_DECL(ERL_NIF_TERM, enif_now_time, (ErlNifEnv *env)); +ERL_NIF_API_FUNC_DECL(ERL_NIF_TERM, enif_cpu_time, (ErlNifEnv *env)); +ERL_NIF_API_FUNC_DECL(ERL_NIF_TERM, enif_make_unique_integer, (ErlNifEnv *env, ErlNifUniqueInteger properties)); /* ** ADD NEW ENTRIES HERE (before this comment) !!! @@ -318,6 +321,9 @@ ERL_NIF_API_FUNC_DECL(int,enif_is_on_dirty_scheduler,(ErlNifEnv*)); # define enif_monotonic_time ERL_NIF_API_FUNC_MACRO(enif_monotonic_time) # define enif_time_offset ERL_NIF_API_FUNC_MACRO(enif_time_offset) # define enif_convert_time_unit ERL_NIF_API_FUNC_MACRO(enif_convert_time_unit) +# define enif_now_time ERL_NIF_API_FUNC_MACRO(enif_now_time) +# define enif_cpu_time ERL_NIF_API_FUNC_MACRO(enif_cpu_time) +# define enif_make_unique_integer ERL_NIF_API_FUNC_MACRO(enif_make_unique_integer) /* ** ADD NEW ENTRIES HERE (before this comment) diff --git a/erts/emulator/beam/erl_trace.c b/erts/emulator/beam/erl_trace.c index 41876b8c62..9033c1b75c 100644 --- a/erts/emulator/beam/erl_trace.c +++ b/erts/emulator/beam/erl_trace.c @@ -176,7 +176,7 @@ take_timestamp(ErtsTraceTimeStamp *tsp, int ts_type) hsz += 3; /* 2-tuple */ raw_unique = erts_raw_get_unique_monotonic_integer(); tsp->u.monotonic.raw_unique = raw_unique; - hsz += erts_raw_unique_monotonic_integer_heap_size(raw_unique); + hsz += erts_raw_unique_monotonic_integer_heap_size(raw_unique, 0); } return hsz; } @@ -216,8 +216,7 @@ write_timestamp(ErtsTraceTimeStamp *tsp, Eterm **hpp) return emtime; raw = tsp->u.monotonic.raw_unique; - unique = erts_raw_make_unique_monotonic_integer_value(hpp, - raw); + unique = erts_raw_make_unique_monotonic_integer_value(hpp, raw, 0); res = TUPLE2(*hpp, emtime, unique); *hpp += 3; return res; diff --git a/erts/emulator/test/nif_SUITE.erl b/erts/emulator/test/nif_SUITE.erl index 84f5699890..d3bf91092f 100644 --- a/erts/emulator/test/nif_SUITE.erl +++ b/erts/emulator/test/nif_SUITE.erl @@ -42,7 +42,9 @@ dirty_nif_exception/1, call_dirty_nif_exception/1, nif_schedule/1, nif_exception/1, call_nif_exception/1, nif_nan_and_inf/1, nif_atom_too_long/1, - nif_monotonic_time/1, nif_time_offset/1, nif_convert_time_unit/1]). + nif_monotonic_time/1, nif_time_offset/1, nif_convert_time_unit/1, + nif_now_time/1, nif_cpu_time/1, nif_unique_integer/1 + ]). -export([many_args_100/100]). @@ -72,7 +74,8 @@ all() -> otp_9668, consume_timeslice, nif_schedule, dirty_nif, dirty_nif_send, dirty_nif_exception, nif_exception, nif_nan_and_inf, nif_atom_too_long, - nif_monotonic_time, nif_time_offset, nif_convert_time_unit + nif_monotonic_time, nif_time_offset, nif_convert_time_unit, + nif_now_time, nif_cpu_time, nif_unique_integer ]. init_per_testcase(_Case, Config) -> @@ -1885,6 +1888,57 @@ chk_ctu(Time, FromTU, [ToTU|ToTUs]) -> chk_ctu(Time, FromTU, ToTUs) end. +nif_now_time(Config) -> + ensure_lib_loaded(Config), + + N1 = now(), + NifN1 = now_time(), + NifN2 = now_time(), + N2 = now(), + true = N1 < NifN1, + true = NifN1 < NifN2, + true = NifN2 < N2. + +nif_cpu_time(Config) -> + ensure_lib_loaded(Config), + + try cpu_time() of + {_, _, _} -> + ok + catch error:badarg -> + {comment, "cpu_time not supported"} + end. + +nif_unique_integer(Config) -> + ensure_lib_loaded(Config), + + UM1 = erlang:unique_integer([monotonic]), + UM2 = unique_integer_nif([monotonic]), + UM3 = erlang:unique_integer([monotonic]), + + true = UM1 < UM2, + true = UM2 < UM3, + + UMP1 = erlang:unique_integer([monotonic, positive]), + UMP2 = unique_integer_nif([monotonic, positive]), + UMP3 = erlang:unique_integer([monotonic, positive]), + + true = 0 =< UMP1, + true = UMP1 < UMP2, + true = UMP2 < UMP3, + + UP1 = erlang:unique_integer([positive]), + UP2 = unique_integer_nif([positive]), + UP3 = erlang:unique_integer([positive]), + + true = 0 =< UP1, + true = 0 =< UP2, + true = 0 =< UP3, + + true = is_integer(unique_integer_nif([])), + true = is_integer(unique_integer_nif([])), + true = is_integer(unique_integer_nif([])). + %% The NIFs: lib_version() -> undefined. call_history() -> ?nif_stub. @@ -1942,6 +1996,7 @@ call_dirty_nif_zero_args() -> ?nif_stub. call_nif_exception(_) -> ?nif_stub. call_nif_nan_or_inf(_) -> ?nif_stub. call_nif_atom_too_long(_) -> ?nif_stub. +unique_integer_nif(_) -> ?nif_stub. %% maps is_map_nif(_) -> ?nif_stub. @@ -1958,7 +2013,8 @@ sorted_list_from_maps_nif(_) -> ?nif_stub. monotonic_time(_) -> ?nif_stub. time_offset(_) -> ?nif_stub. convert_time_unit(_,_,_) -> ?nif_stub. - +now_time() -> ?nif_stub. +cpu_time() -> ?nif_stub. nif_stub_error(Line) -> exit({nif_not_loaded,module,?MODULE,line,Line}). diff --git a/erts/emulator/test/nif_SUITE_data/nif_SUITE.c b/erts/emulator/test/nif_SUITE_data/nif_SUITE.c index 1acb270d1f..1960689590 100644 --- a/erts/emulator/test/nif_SUITE_data/nif_SUITE.c +++ b/erts/emulator/test/nif_SUITE_data/nif_SUITE.c @@ -1978,6 +1978,36 @@ static ERL_NIF_TERM convert_time_unit(ErlNifEnv* env, int argc, const ERL_NIF_TE return enif_make_int64(env, enif_convert_time_unit(val, from, to)); } +static ERL_NIF_TERM now_time(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{ + return enif_now_time(env); +} + +static ERL_NIF_TERM cpu_time(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{ + return enif_cpu_time(env); +} + +static ERL_NIF_TERM unique_integer(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{ + ERL_NIF_TERM atom_pos = enif_make_atom(env,"positive"), + atom_mon = enif_make_atom(env,"monotonic"); + ERL_NIF_TERM opts = argv[0], opt; + ErlNifUniqueInteger properties = 0; + + while (!enif_is_empty_list(env, opts)) { + if (!enif_get_list_cell(env, opts, &opt, &opts)) + return enif_make_badarg(env); + + if (enif_compare(opt, atom_pos) == 0) + properties |= ERL_NIF_UNIQUE_POSITIVE; + if (enif_compare(opt, atom_mon) == 0) + properties |= ERL_NIF_UNIQUE_MONOTONIC; + } + + return enif_make_unique_integer(env, properties); +} + static ErlNifFunc nif_funcs[] = { {"lib_version", 0, lib_version}, @@ -2050,8 +2080,10 @@ static ErlNifFunc nif_funcs[] = {"sorted_list_from_maps_nif", 1, sorted_list_from_maps_nif}, {"monotonic_time", 1, monotonic_time}, {"time_offset", 1, time_offset}, - {"convert_time_unit", 3, convert_time_unit} + {"convert_time_unit", 3, convert_time_unit}, + {"now_time", 0, now_time}, + {"cpu_time", 0, cpu_time}, + {"unique_integer_nif", 1, unique_integer} }; ERL_NIF_INIT(nif_SUITE,nif_funcs,load,reload,upgrade,unload) - -- cgit v1.2.3