diff options
-rw-r--r-- | erts/emulator/Makefile.in | 3 | ||||
-rw-r--r-- | erts/emulator/beam/dist.c | 29 | ||||
-rw-r--r-- | erts/emulator/beam/erl_bif_info.c | 28 | ||||
-rw-r--r-- | erts/emulator/beam/erl_global_literals.c | 69 | ||||
-rw-r--r-- | erts/emulator/beam/erl_global_literals.h | 34 | ||||
-rw-r--r-- | erts/emulator/beam/erl_process_dump.c | 7 | ||||
-rw-r--r-- | erts/emulator/test/binary_SUITE.erl | 56 | ||||
-rw-r--r-- | lib/observer/test/crashdump_helper.erl | 23 | ||||
-rw-r--r-- | lib/observer/test/crashdump_viewer_SUITE.erl | 28 |
9 files changed, 221 insertions, 56 deletions
diff --git a/erts/emulator/Makefile.in b/erts/emulator/Makefile.in index 6c25a28116..dfaeef9b39 100644 --- a/erts/emulator/Makefile.in +++ b/erts/emulator/Makefile.in @@ -950,7 +950,8 @@ RUN_OBJS += \ $(OBJDIR)/erl_msacc.o $(OBJDIR)/erl_lock_flags.o \ $(OBJDIR)/erl_io_queue.o $(OBJDIR)/erl_db_catree.o \ $(ESOCK_RUN_OBJS) $(OBJDIR)/erl_flxctr.o \ - $(OBJDIR)/erl_nfunc_sched.o + $(OBJDIR)/erl_nfunc_sched.o \ + $(OBJDIR)/erl_global_literals.o LTTNG_OBJS = $(OBJDIR)/erlang_lttng.o diff --git a/erts/emulator/beam/dist.c b/erts/emulator/beam/dist.c index de7309b248..eac522e165 100644 --- a/erts/emulator/beam/dist.c +++ b/erts/emulator/beam/dist.c @@ -46,6 +46,7 @@ #include "erl_thr_progress.h" #include "dtrace-wrapper.h" #include "erl_proc_sig_queue.h" +#include "erl_global_literals.h" #define DIST_CTL_DEFAULT_SIZE 64 @@ -1030,14 +1031,6 @@ trap_function(Eterm func, int arity) return erts_export_put(am_erlang, func, arity); } -/* - * Sync with dist_util.erl: - * - * -record(erts_dflags, - * {default, mandatory, addable, rejectable, strict_order}). - */ -static Eterm erts_dflags_record; - static BIF_RETTYPE spawn_request_yield_3(BIF_ALIST_3); void init_dist(void) @@ -1069,11 +1062,16 @@ void init_dist(void) am_erts_internal, am_spawn_request_yield, 3, spawn_request_yield_3); { - Eterm *hp_start, *hp, **hpp = NULL; + Eterm *hp_start, *hp, **hpp = NULL, tuple; Uint sz = 0, *szp = &sz; while (1) { - erts_dflags_record = - erts_bld_tuple(hpp, szp, 6, + /* + * Sync with dist_util.erl: + * + * -record(erts_dflags, + * {default, mandatory, addable, rejectable, strict_order}). + */ + tuple = erts_bld_tuple(hpp, szp, 6, am_erts_dflags, erts_bld_uint64(hpp, szp, DFLAG_DIST_DEFAULT), erts_bld_uint64(hpp, szp, DFLAG_DIST_MANDATORY), @@ -1081,12 +1079,12 @@ void init_dist(void) erts_bld_uint64(hpp, szp, DFLAG_DIST_REJECTABLE), erts_bld_uint64(hpp, szp, DFLAG_DIST_STRICT_ORDER)); if (hpp) { - ASSERT(is_value(erts_dflags_record)); + ASSERT(is_value(tuple)); ASSERT(hp == hp_start + sz); - erts_set_literal_tag(&erts_dflags_record, hp_start, sz); + erts_register_global_literal(ERTS_LIT_DFLAGS_RECORD, tuple); break; } - hp = hp_start = erts_alloc(ERTS_ALC_T_LITERAL, sz*sizeof(Eterm)); + hp = hp_start = erts_alloc_global_literal(ERTS_LIT_DFLAGS_RECORD, sz); hpp = &hp; szp = NULL; } @@ -5032,8 +5030,7 @@ BIF_RETTYPE erts_internal_get_dflags_0(BIF_ALIST_0) szp = NULL; } } - return erts_dflags_record; - + return erts_get_global_literal(ERTS_LIT_DFLAGS_RECORD); } BIF_RETTYPE erts_internal_get_creation_0(BIF_ALIST_0) diff --git a/erts/emulator/beam/erl_bif_info.c b/erts/emulator/beam/erl_bif_info.c index f20cce7ee4..fde980757b 100644 --- a/erts/emulator/beam/erl_bif_info.c +++ b/erts/emulator/beam/erl_bif_info.c @@ -55,6 +55,7 @@ #ifdef HIPE #include "hipe_arch.h" #endif +#include "erl_global_literals.h" #ifdef ERTS_ENABLE_LOCK_COUNT #include "erl_lock_count.h" @@ -151,10 +152,6 @@ static char erts_system_version[] = ("Erlang/OTP " ERLANG_OTP_RELEASE # define PERFMON_GETPCR _IOR('P', 2, unsigned long long) #endif -/* Cached, pre-built {OsType,OsFlavor} and {Major,Minor,Build} tuples */ -static Eterm os_type_tuple; -static Eterm os_version_tuple; - static Eterm current_function(Process* p, ErtsHeapFactory *hfact, Process* rp, int full_info, Uint reserve_size, int flags); @@ -2665,7 +2662,7 @@ BIF_RETTYPE system_info_1(BIF_ALIST_1) NIL)); } else if (BIF_ARG_1 == am_os_type) { - BIF_RET(os_type_tuple); + BIF_RET(erts_get_global_literal(ERTS_LIT_OS_TYPE)); } else if (BIF_ARG_1 == am_allocator) { BIF_RET(erts_allocator_options((void *) BIF_P)); @@ -2685,7 +2682,7 @@ BIF_RETTYPE system_info_1(BIF_ALIST_1) BIF_RET(am_false); } else if (BIF_ARG_1 == am_os_version) { - BIF_RET(os_version_tuple); + BIF_RET(erts_get_global_literal(ERTS_LIT_OS_VERSION)); } else if (BIF_ARG_1 == am_version) { int n = sys_strlen(ERLANG_VERSION); @@ -5486,21 +5483,22 @@ static void os_info_init(void) int major, minor, build; char* buf = erts_alloc(ERTS_ALC_T_TMP, 1024); /* More than enough */ Eterm* hp; + Eterm tuple; os_flavor(buf, 1024); flav = erts_atom_put((byte *) buf, sys_strlen(buf), ERTS_ATOM_ENC_LATIN1, 1); erts_free(ERTS_ALC_T_TMP, (void *) buf); - hp = erts_alloc(ERTS_ALC_T_LITERAL, (3+4)*sizeof(Eterm)); - os_type_tuple = TUPLE2(hp, type, flav); - erts_set_literal_tag(&os_type_tuple, hp, 3); + hp = erts_alloc_global_literal(ERTS_LIT_OS_TYPE, 3); + tuple = TUPLE2(hp, type, flav); + erts_register_global_literal(ERTS_LIT_OS_TYPE, tuple); - hp += 3; + hp = erts_alloc_global_literal(ERTS_LIT_OS_VERSION, 4); os_version(&major, &minor, &build); - os_version_tuple = TUPLE3(hp, - make_small(major), - make_small(minor), - make_small(build)); - erts_set_literal_tag(&os_version_tuple, hp, 4); + tuple = TUPLE3(hp, + make_small(major), + make_small(minor), + make_small(build)); + erts_register_global_literal(ERTS_LIT_OS_VERSION, tuple); } void diff --git a/erts/emulator/beam/erl_global_literals.c b/erts/emulator/beam/erl_global_literals.c new file mode 100644 index 0000000000..c3e7b8a70b --- /dev/null +++ b/erts/emulator/beam/erl_global_literals.c @@ -0,0 +1,69 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2020. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * %CopyrightEnd% + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include "sys.h" +#include "global.h" +#include "erl_global_literals.h" + +struct literal { + Eterm term; + ErtsLiteralArea* area; +}; + +static struct literal literals[ERTS_NUM_GLOBAL_LITERALS]; + +Eterm* erts_alloc_global_literal(Uint index, Uint sz) +{ + ErtsLiteralArea* area; + Uint area_sz; + + ASSERT(index < ERTS_NUM_GLOBAL_LITERALS); + area_sz = sizeof(ErtsLiteralArea) + (sz-1)*sizeof(Eterm); + area = erts_alloc(ERTS_ALC_T_LITERAL, area_sz); + area->end = area->start + sz; + literals[index].area = area; + return area->start; +} + +void erts_register_global_literal(Uint index, Eterm term) +{ + Eterm* start; + + ASSERT(index < ERTS_NUM_GLOBAL_LITERALS); + start = literals[index].area->start; + erts_set_literal_tag(&term, start, literals[index].area->end - start); + literals[index].term = term; +} + +Eterm erts_get_global_literal(Uint index) +{ + ASSERT(index < ERTS_NUM_GLOBAL_LITERALS); + return literals[index].term; +} + +ErtsLiteralArea* erts_get_global_literal_area(Uint index) +{ + ASSERT(index < ERTS_NUM_GLOBAL_LITERALS); + return literals[index].area; +} diff --git a/erts/emulator/beam/erl_global_literals.h b/erts/emulator/beam/erl_global_literals.h new file mode 100644 index 0000000000..15e873479d --- /dev/null +++ b/erts/emulator/beam/erl_global_literals.h @@ -0,0 +1,34 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1996-2020. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * %CopyrightEnd% + */ + +#ifndef __ERL_GLOBAL_LITERALS_H__ +#define __ERL_GLOBAL_LITERALS_H__ + +#define ERTS_LIT_OS_TYPE 0 +#define ERTS_LIT_OS_VERSION 1 +#define ERTS_LIT_DFLAGS_RECORD 2 + +#define ERTS_NUM_GLOBAL_LITERALS 3 + +Eterm* erts_alloc_global_literal(Uint index, Uint sz); +void erts_register_global_literal(Uint index, Eterm term); +Eterm erts_get_global_literal(Uint index); +ErtsLiteralArea* erts_get_global_literal_area(Uint index); +#endif diff --git a/erts/emulator/beam/erl_process_dump.c b/erts/emulator/beam/erl_process_dump.c index a6c1ae14b5..69ff526e14 100644 --- a/erts/emulator/beam/erl_process_dump.c +++ b/erts/emulator/beam/erl_process_dump.c @@ -36,6 +36,7 @@ #define ERTS_WANT_EXTERNAL_TAGS #include "external.h" #include "erl_proc_sig_queue.h" +#include "erl_global_literals.h" #define PTR_FMT "%bpX" #define ETERM_FMT "%beX" @@ -840,6 +841,12 @@ dump_literals(fmtfn_t to, void *to_arg) erts_rlock_old_code(code_ix); erts_print(to, to_arg, "=literals\n"); + + for (i = 0; i < ERTS_NUM_GLOBAL_LITERALS; i++) { + ErtsLiteralArea* area = erts_get_global_literal_area(i); + dump_module_literals(to, to_arg, area); + } + for (i = 0; i < num_lit_areas; i++) { if (lit_areas[i]->off_heap) { dump_module_literals(to, to_arg, lit_areas[i]); diff --git a/erts/emulator/test/binary_SUITE.erl b/erts/emulator/test/binary_SUITE.erl index 0dc2e84290..49d2dfb983 100644 --- a/erts/emulator/test/binary_SUITE.erl +++ b/erts/emulator/test/binary_SUITE.erl @@ -475,10 +475,7 @@ t2b_system_limit(Config) when is_list(Config) -> memsup:get_system_memory_data()) of Memory when is_integer(Memory), Memory > 6*1024*1024*1024 -> - test_t2b_system_limit(term_to_binary, fun erlang:term_to_binary/1, fun erlang:term_to_binary/2), - test_t2b_system_limit(term_to_iovec, fun erlang:term_to_iovec/1, fun erlang:term_to_iovec/2), - garbage_collect(), - ok; + do_t2b_system_limit(); _ -> {skipped, "Not enough memory on this machine"} end; @@ -486,37 +483,52 @@ t2b_system_limit(Config) when is_list(Config) -> {skipped, "Only interesting on 64-bit builds"} end. -test_t2b_system_limit(Name, F1, F2) -> - io:format("Creating HugeBin~n", []), - Bits = ((1 bsl 32)+1)*8, - HugeBin = <<0:Bits>>, - +do_t2b_system_limit() -> + F = fun() -> + io:format("Creating HugeBin~n", []), + Bits = (1 bsl 32) + 1, + HugeBin = <<0:Bits/unit:8>>, + test_t2b_system_limit(HugeBin, term_to_binary, + fun erlang:term_to_binary/1, + fun erlang:term_to_binary/2), + test_t2b_system_limit(HugeBin, term_to_iovec, + fun erlang:term_to_iovec/1, + fun erlang:term_to_iovec/2), + garbage_collect(), + ok + end, + Opts = [{args, "-pa " ++ filename:dirname(code:which(?MODULE))}], + {ok,Node} = test_server:start_node(?FUNCTION_NAME, slave, Opts), + erpc:call(Node, F). + +test_t2b_system_limit(HugeBin, Name, F1, F2) -> io:format("Testing ~p(HugeBin)~n", [Name]), - {'EXIT',{system_limit,[{erlang,Name, - [HugeBin], - _} |_]}} = (catch F1(HugeBin)), + {'EXIT',{system_limit,[{erlang,Name,[HugeBin],_}|_]}} = + t2b_eval(fun() -> F1(HugeBin) end), io:format("Testing ~p(HugeBin, [compressed])~n", [Name]), - {'EXIT',{system_limit,[{erlang,Name, - [HugeBin, [compressed]], - _} |_]}} = (catch F2(HugeBin, [compressed])), + {'EXIT',{system_limit,[{erlang,Name,[HugeBin,[compressed]],_}|_]}} = + t2b_eval(fun() -> F2(HugeBin, [compressed]) end), %% Check that it works also after we have trapped... io:format("Creating HugeListBin~n", []), - HugeListBin = [lists:duplicate(2000000,2000000), HugeBin], + HugeListBin = [lists:duplicate(2000000, 2000000), HugeBin], io:format("Testing ~p(HugeListBin)~n", [Name]), - {'EXIT',{system_limit,[{erlang,Name, - [HugeListBin], - _} |_]}} = (catch F1(HugeListBin)), + {'EXIT',{system_limit,[{erlang,Name,[HugeListBin],_}|_]}} = + t2b_eval(fun() -> F1(HugeListBin) end), io:format("Testing ~p(HugeListBin, [compressed])~n", [Name]), - {'EXIT',{system_limit,[{erlang,Name, - [HugeListBin, [compressed]], - _} |_]}} = (catch F2(HugeListBin, [compressed])), + {'EXIT',{system_limit,[{erlang,Name,[HugeListBin,[compressed]],_}|_]}} = + t2b_eval(fun() -> F2(HugeListBin, [compressed]) end), ok. +t2b_eval(F) -> + Result = (catch F()), + io:put_chars(io_lib:format("~P\n", [Result,100])), + Result. + term_to_iovec(Config) when is_list(Config) -> Bin = list_to_binary(lists:duplicate(1000,100)), Bin2 = list_to_binary(lists:duplicate(65,100)), diff --git a/lib/observer/test/crashdump_helper.erl b/lib/observer/test/crashdump_helper.erl index 5c77330e49..0f0947065a 100644 --- a/lib/observer/test/crashdump_helper.erl +++ b/lib/observer/test/crashdump_helper.erl @@ -23,7 +23,8 @@ dump_maps/0,create_maps/0, create_binaries/0,create_sub_binaries/1, dump_persistent_terms/0, - create_persistent_terms/0]). + create_persistent_terms/0, + dump_global_literals/0]). -compile(r20). -include_lib("common_test/include/ct.hrl"). @@ -207,3 +208,23 @@ create_persistent_terms() -> persistent_term:put({?MODULE,first}, {pid,42.0}), persistent_term:put({?MODULE,second}, [1,2,3]), {persistent_term:get({?MODULE,first}),persistent_term:get({?MODULE,second})}. + +%%% +%%% Test dumping of global literals such as the tuple returned from os:type/0 +%%% (from OTP 23.1). +%%% + +dump_global_literals() -> + Parent = self(), + F = fun() -> + register(aaaaaaaa_global_literals, self()), + put(global_literals, {os:type(),os:version()}), + Parent ! {self(),done}, + receive _ -> ok end + end, + Pid = spawn_link(F), + receive + {Pid,done} -> + unlink(Pid), + {ok,Pid} + end. diff --git a/lib/observer/test/crashdump_viewer_SUITE.erl b/lib/observer/test/crashdump_viewer_SUITE.erl index 31cf7011d4..4e0fd68f50 100644 --- a/lib/observer/test/crashdump_viewer_SUITE.erl +++ b/lib/observer/test/crashdump_viewer_SUITE.erl @@ -619,6 +619,21 @@ special(File,Procs) -> Pts = proplists:get_value(pts,Dict), io:format(" persistent terms ok",[]), ok; + ".global_literals" -> + %% I registered a process as aaaaaaaa_global_literals in + %% the dump to make sure it will be the first in the list + %% when sorted on names. + [#proc{pid=Pid0,name=Name}|_Rest] = lists:keysort(#proc.name,Procs), + "aaaaaaaa_global_literals" = Name, + Pid = pid_to_list(Pid0), + {ok,ProcDetails=#proc{},[]} = crashdump_viewer:proc_details(Pid), + io:format(" process details ok",[]), + + #proc{dict=Dict} = ProcDetails, + Globals = proplists:get_value(global_literals,Dict), + Globals = {os:type(),os:version()}, + io:format(" global_literals ok",[]), + ok; _ -> ok end, @@ -704,9 +719,10 @@ do_create_dumps(DataDir,Rel) -> CD6 = dump_with_unicode_atoms(DataDir,Rel,"unicode"), CD7 = dump_with_maps(DataDir,Rel,"maps"), CD8 = dump_with_persistent_terms(DataDir,Rel,"persistent_terms"), + CD9 = dump_with_global_literals(DataDir,Rel,"global_literals"), TruncDumpMod = truncate_dump_mod(CD1), TruncatedDumpsBinary = truncate_dump_binary(CD1), - {[CD1,CD2,CD3,CD4,CD5,CD6,CD7,CD8, + {[CD1,CD2,CD3,CD4,CD5,CD6,CD7,CD8,CD9, TruncDumpMod|TruncatedDumpsBinary], DosDump}; _ -> @@ -886,6 +902,16 @@ dump_with_persistent_terms(DataDir,Rel,DumpName) -> ?t:stop_node(n1), CD. +dump_with_global_literals(DataDir,Rel,DumpName) -> + Opt = rel_opt(Rel), + Pz = "-pz \"" ++ filename:dirname(code:which(?MODULE)) ++ "\"", + PzOpt = [{args,Pz}], + {ok,N1} = ?t:start_node(n1,peer,Opt ++ PzOpt), + {ok,_Pid} = rpc:call(N1,crashdump_helper,dump_global_literals,[]), + CD = dump(N1,DataDir,Rel,DumpName), + ?t:stop_node(n1), + CD. + dump(Node,DataDir,Rel,DumpName) -> Crashdump = filename:join(DataDir, dump_prefix(Rel)++DumpName), rpc:call(Node,os,putenv,["ERL_CRASH_DUMP",Crashdump]), |