aboutsummaryrefslogtreecommitdiffstats
path: root/erts/emulator
diff options
context:
space:
mode:
Diffstat (limited to 'erts/emulator')
-rw-r--r--erts/emulator/Makefile.in2
-rw-r--r--erts/emulator/beam/atom.h3
-rw-r--r--erts/emulator/beam/beam_bp.c3
-rw-r--r--erts/emulator/beam/beam_emu.c22
-rw-r--r--erts/emulator/beam/benchmark.c301
-rw-r--r--erts/emulator/beam/benchmark.h295
-rw-r--r--erts/emulator/beam/big.h9
-rw-r--r--erts/emulator/beam/erl_gc.c5
-rw-r--r--erts/emulator/beam/erl_init.c4
-rw-r--r--erts/emulator/beam/erl_map.c48
-rw-r--r--erts/emulator/beam/erl_map.h8
-rw-r--r--erts/emulator/beam/erl_message.c19
-rw-r--r--erts/emulator/beam/erl_msacc.c190
-rw-r--r--erts/emulator/beam/erl_msacc.h69
-rw-r--r--erts/emulator/beam/erl_nif.c2
-rw-r--r--erts/emulator/beam/erl_process.c28
-rw-r--r--erts/emulator/beam/erl_process.h3
-rw-r--r--erts/emulator/beam/erl_trace.c4
-rw-r--r--erts/emulator/beam/export.h6
-rw-r--r--erts/emulator/beam/global.h1
-rw-r--r--erts/emulator/beam/hash.h2
-rw-r--r--erts/emulator/beam/index.h5
-rw-r--r--erts/emulator/beam/module.h2
-rw-r--r--erts/emulator/beam/safe_hash.h5
-rw-r--r--erts/emulator/hipe/hipe_amd64_asm.m422
-rw-r--r--erts/emulator/hipe/hipe_amd64_bifs.m43
-rw-r--r--erts/emulator/hipe/hipe_amd64_glue.S2
-rw-r--r--erts/emulator/hipe/hipe_arm_asm.m432
-rw-r--r--erts/emulator/hipe/hipe_arm_bifs.m433
-rw-r--r--erts/emulator/hipe/hipe_arm_glue.S4
-rw-r--r--erts/emulator/hipe/hipe_bif1.c754
-rw-r--r--erts/emulator/hipe/hipe_bif1.tab21
-rw-r--r--erts/emulator/hipe/hipe_bif_list.m447
-rw-r--r--erts/emulator/hipe/hipe_gc.c4
-rw-r--r--erts/emulator/hipe/hipe_mkliterals.c6
-rw-r--r--erts/emulator/hipe/hipe_ppc_bifs.m436
-rw-r--r--erts/emulator/hipe/hipe_process.h6
-rw-r--r--erts/emulator/hipe/hipe_sparc_bifs.m434
-rw-r--r--erts/emulator/hipe/hipe_x86_bifs.m43
-rw-r--r--erts/emulator/sys/unix/erl_child_setup.c103
-rw-r--r--erts/emulator/sys/unix/erl_unix_sys.h2
-rw-r--r--erts/emulator/sys/unix/sys_drivers.c55
-rw-r--r--erts/emulator/test/port_SUITE.erl127
-rw-r--r--erts/emulator/test/trace_local_SUITE.erl8
44 files changed, 656 insertions, 1682 deletions
diff --git a/erts/emulator/Makefile.in b/erts/emulator/Makefile.in
index 2212aed5e0..6c4b30020a 100644
--- a/erts/emulator/Makefile.in
+++ b/erts/emulator/Makefile.in
@@ -744,7 +744,7 @@ EMU_OBJS = \
$(OBJDIR)/beam_ranges.o
RUN_OBJS = \
- $(OBJDIR)/erl_pbifs.o $(OBJDIR)/benchmark.o \
+ $(OBJDIR)/erl_pbifs.o \
$(OBJDIR)/erl_alloc.o $(OBJDIR)/erl_mtrace.o \
$(OBJDIR)/erl_alloc_util.o $(OBJDIR)/erl_goodfit_alloc.o \
$(OBJDIR)/erl_bestfit_alloc.o $(OBJDIR)/erl_afit_alloc.o \
diff --git a/erts/emulator/beam/atom.h b/erts/emulator/beam/atom.h
index fbd0528009..ae60904785 100644
--- a/erts/emulator/beam/atom.h
+++ b/erts/emulator/beam/atom.h
@@ -21,10 +21,7 @@
#ifndef __ATOM_H__
#define __ATOM_H__
-#ifndef __INDEX_H__
#include "index.h"
-#endif
-
#include "erl_atom_table.h"
#define MAX_ATOM_CHARACTERS 255
diff --git a/erts/emulator/beam/beam_bp.c b/erts/emulator/beam/beam_bp.c
index 8489897d3a..920c8b1ed0 100644
--- a/erts/emulator/beam/beam_bp.c
+++ b/erts/emulator/beam/beam_bp.c
@@ -858,7 +858,8 @@ erts_bif_trace(int bif_index, Process* p, Eterm* args, BeamInstr* I)
if (flags & MATCH_SET_RX_TRACE) {
erts_trace_return(p, ep->code, result, &ERTS_TRACER(p));
}
- if (flags & MATCH_SET_RETURN_TO_TRACE) {
+ if (flags & MATCH_SET_RETURN_TO_TRACE &&
+ IS_TRACED_FL(p, F_TRACE_RETURN_TO)) {
/* can only happen if(local)*/
if (applying) {
/* Apply of BIF, cp is in calling function */
diff --git a/erts/emulator/beam/beam_emu.c b/erts/emulator/beam/beam_emu.c
index c6258287c4..b90c4dedea 100644
--- a/erts/emulator/beam/beam_emu.c
+++ b/erts/emulator/beam/beam_emu.c
@@ -2826,13 +2826,7 @@ do { \
goto context_switch3;
}
- if (ERTS_MSACC_IS_ENABLED_CACHED_X()) {
- if (GET_BIF_MODULE(Arg(0)) == am_ets) {
- ERTS_MSACC_SET_STATE_CACHED_M_X(ERTS_MSACC_STATE_ETS);
- } else {
- ERTS_MSACC_SET_STATE_CACHED_M_X(ERTS_MSACC_STATE_BIF);
- }
- }
+ ERTS_MSACC_SET_BIF_STATE_CACHED_X(GET_BIF_MODULE(Arg(0)), GET_BIF_ADDRESS(Arg(0)));
bf = GET_BIF_ADDRESS(Arg(0));
@@ -3593,13 +3587,7 @@ do { \
goto context_switch;
}
- if (ERTS_MSACC_IS_ENABLED_CACHED_X()) {
- if ((Eterm)I[-3] == am_ets) {
- ERTS_MSACC_SET_STATE_CACHED_M_X(ERTS_MSACC_STATE_ETS);
- } else {
- ERTS_MSACC_SET_STATE_CACHED_M_X(ERTS_MSACC_STATE_BIF);
- }
- }
+ ERTS_MSACC_SET_BIF_STATE_CACHED_X((Eterm)I[-3], (BifFunction)Arg(0));
c_p->current = I-3; /* In case we apply process_info/1,2 or load_nif/1 */
c_p->i = I; /* In case we apply check_process_code/2. */
@@ -7017,7 +7005,11 @@ update_map_assoc(Process* p, Eterm* reg, Eterm map, BeamInstr* I)
/* The expensive case, need to build a hashmap */
if (n > MAP_SMALL_MAP_LIMIT) {
- res = erts_hashmap_from_ks_and_vs(p,flatmap_get_keys(mp),flatmap_get_values(mp),n);
+ ErtsHeapFactory factory;
+ erts_factory_proc_init(&factory, p);
+ res = erts_hashmap_from_ks_and_vs(&factory,flatmap_get_keys(mp),
+ flatmap_get_values(mp),n);
+ erts_factory_close(&factory);
}
return res;
}
diff --git a/erts/emulator/beam/benchmark.c b/erts/emulator/beam/benchmark.c
deleted file mode 100644
index c8409784ef..0000000000
--- a/erts/emulator/beam/benchmark.c
+++ /dev/null
@@ -1,301 +0,0 @@
-/*
- * %CopyrightBegin%
- *
- * Copyright Ericsson AB 2002-2016. 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 "benchmark.h"
-
-#ifdef BM_COUNTERS
-unsigned long long processes_busy;
-unsigned long long processes_spawned;
-unsigned long long messages_sent;
-unsigned long long messages_copied;
-unsigned long long messages_ego;
-unsigned long long minor_gc;
-unsigned long long major_gc;
-#endif /* BM_COUNTERS */
-
-#ifdef BM_TIMERS
-
-/* assuming Solaris */
-#include <time.h>
-BM_TIMER_T system_clock;
-
-unsigned long local_pause_times[MAX_PAUSE_TIME];
-unsigned long pause_times[MAX_PAUSE_TIME];
-unsigned long pause_times_old[MAX_PAUSE_TIME];
-
-BM_TIMER_T mmu;
-BM_TIMER_T mmu_counter;
-
-BM_NEW_TIMER(timer);
-BM_NEW_TIMER(system);
-BM_NEW_TIMER(gc);
-BM_NEW_TIMER(minor_gc);
-BM_NEW_TIMER(major_gc);
-BM_NEW_TIMER(minor_global_gc);
-BM_NEW_TIMER(major_global_gc);
-BM_NEW_TIMER(send);
-BM_NEW_TIMER(copy);
-BM_NEW_TIMER(size);
-BM_NEW_TIMER(max_minor);
-BM_NEW_TIMER(max_major);
-BM_NEW_TIMER(max_global_minor);
-BM_NEW_TIMER(max_global_major);
-BM_NEW_TIMER(misc0);
-BM_NEW_TIMER(misc1);
-BM_NEW_TIMER(misc2);
-#endif /* BM_TIMERS */
-
-#ifdef BM_HEAP_SIZES
-unsigned long long max_used_heap;
-unsigned long long max_allocated_heap;
-unsigned long long max_used_global_heap;
-unsigned long long max_allocated_global_heap;
-#endif /* BM_HEAP_SIZES */
-
-#ifdef BM_MESSAGE_SIZES
-unsigned long long words_sent;
-unsigned long long words_copied;
-unsigned long long words_prealloc;
-unsigned long long message_sizes[1000];
-#endif /* BM_MESSAGE_SIZES */
-
-/*****
- * The following functions have to be defined, but they only have contents
- * if certain keywords are defined.
- */
-
-void init_benchmarking()
-{
-#ifdef BM_TIMERS
- int i;
- for (i = 0; i < 1000; i++)
- {
- BM_START_TIMER(system);
- BM_STOP_TIMER(system);
- }
- timer_time = system_time / 1000;
-
- for (i = 0; i < MAX_PAUSE_TIME; i++) {
- local_pause_times[i] = 0;
- pause_times[i] = 0;
- pause_times_old[i] = 0;
- }
-
- mmu = 0;
- mmu_counter = 0;
-
- BM_MMU_INIT();
-#endif /* BM_TIMERS */
-
-#ifdef BM_COUNTERS
- processes_busy = 0;
- processes_spawned = 0;
- messages_sent = 0;
- messages_copied = 0;
- messages_ego = 0;
- minor_gc = 0;
- major_gc = 0;
-#endif /* BM_COUNTERS */
-
-#ifdef BM_HEAP_SIZES
- max_used_heap = 0;
- max_allocated_heap = 0;
- max_used_global_heap = 0;
- max_allocated_global_heap = 0;
-#endif /* BM_HEAP_SIZES */
-
-#ifdef BM_MESSAGE_SIZES
- words_sent = 0;
- words_copied = 0;
- words_prealloc = 0;
- {
- int i;
- for (i = 0; i < 1000; i++)
- message_sizes[i] = 0;
- }
-#endif /* BM_MESSAGE_SIZES */
-}
-
-void save_statistics()
-{
-#ifdef BM_STATISTICS
- FILE *file = fopen(BM_STATISTICS_FILE,"a");
- long i = 0;
-
- if (file)
- {
- erts_fprintf(file,"-------------------------------------------------------------------------\n");
- erts_fprintf(file,"The counters are reset at system start and are sums over the entire node.\n");
- erts_fprintf(file,"You may reset them manually using the BIFs in the module hipe_bifs.\n");
- erts_fprintf(file,"All times are given in milliseconds.\n");
- erts_fprintf(file,"-------------------------------------------------------------------------\n");
-
- erts_fprintf(file,"Node: %T\n",erts_this_node->sysname);
-
-#ifdef BM_COUNTERS
- erts_fprintf(file,"Number of processes spawned: %lld\n",processes_spawned);
- erts_fprintf(file,"Number of local minor GCs: %lld\n",minor_gc);
- erts_fprintf(file,"Number of local major GCs: %lld\n",major_gc);
- erts_fprintf(file,"Number of messages sent: %lld\n",messages_sent);
- erts_fprintf(file,"Number of messages copied: %lld\n",messages_copied);
- erts_fprintf(file,"Number of messages sent to self: %lld\n",messages_ego);
-#endif /* BM_COUNTERS */
-
-#ifdef BM_MESSAGE_SIZES
- erts_fprintf(file,"Number of words sent: %lld\n",words_sent);
- erts_fprintf(file,"Number of words copied: %lld\n",words_copied);
- erts_fprintf(file,"Number of words preallocated: %lld\n",words_prealloc);
-#endif /* BM_MESSAGE_SIZES */
-
-#ifdef BM_HEAP_SIZES
- erts_fprintf(file,"Biggest local heap used (in words): %lld\n",max_used_heap);
- erts_fprintf(file,"Biggest local heap allocated (in words): %lld\n",max_allocated_heap);
- erts_fprintf(file,"Biggest global heap used (in words): %lld\n",max_used_global_heap);
- erts_fprintf(file,"Biggest global heap allocated (in words): %lld\n",max_allocated_global_heap);
-#endif /* BM_HEAP_SIZES */
-
-#ifdef BM_TIMERS
- erts_fprintf(file,"--- The total active system time is the sum of all times below ---\n");
- BM_TIME_PRINTER("Mutator time",system_time);
- BM_TIME_PRINTER("Time spent in send (excluding size & copy)",send_time);
- BM_TIME_PRINTER("Time spent in size",size_time);
- BM_TIME_PRINTER("Time spent in copy",copy_time);
- BM_TIME_PRINTER("Time spent in local minor GC",minor_gc_time);
- BM_TIME_PRINTER("Time spent in local major GC",major_gc_time);
- BM_TIME_PRINTER("Time spent in global minor GC",minor_global_gc_time);
- BM_TIME_PRINTER("Time spent in global major GC",major_global_gc_time);
- erts_fprintf(file,"---\n");
- BM_TIME_PRINTER("Maximum time spent in one separate local minor GC",max_minor_time);
- BM_TIME_PRINTER("Maximum time spent in one separate local major GC",max_major_time);
- BM_TIME_PRINTER("Maximum time spent in one separate global minor GC",max_global_minor_time);
- BM_TIME_PRINTER("Maximum time spent in one separate global major GC",max_global_major_time);
-#endif /* BM_TIMERS */
-
-#if 0
- /* Save a log file for import into excel */
-
- long long total_time, n;
- long left, right, mid;
-
-#ifdef BM_COUNTERS
- erts_fprintf(file,"Spawns\tLocalGC\tMAGC\tMessages\tMutator_t\tLocalGC_t\tMAGC_t\tLocMaxP\tLocMeanP\tLocGeoMP\tMAMaxP\tMAMeanP\tMAGeoMP\t\tCMAGC\tCMAGC_t\n");
- erts_fprintf(file,"%lld\t%lld\t%lld\t%lld\t",
- processes_spawned,
- minor_garbage_cols + major_garbage_cols,
- minor_global_garbage_cols + major_global_garbage_cols,
- messages_sent);
-#endif /* BM_COUNTERS */
-
-#ifdef BM_TIMERS
- erts_fprintf(file,"%lld\t%lld\t%lld\t",
- (long long)(system_time + send_time + size_time + copy_time),
- (long long)(minor_gc_time + major_gc_time),
- (long long)(minor_global_gc_time + major_global_gc_time));
-
- total_time = 0; n = 0;
- left = 0; right = 0; mid = 0;
- for (i = 0; i < MAX_PAUSE_TIME; i++) {
- total_time += local_pause_times[i] * i;
- n += local_pause_times[i];
- if (i > mid)
- right += local_pause_times[i];
- while(right > left) {
- left += local_pause_times[mid++];
- right -= local_pause_times[mid];
- }
- }
- erts_fprintf(file,"%lld\t%lld\t%ld\t",
- (long long)((max_minor_time > max_major_time ?
- max_minor_time :
- max_major_time)*1000),
- total_time / n,
- mid);
-
- total_time = 0; n = 0;
- left = 0; right = 0; mid = 0;
- for (i = 0; i < MAX_PAUSE_TIME; i++) {
- if (pause_times[i] > 0) {
- total_time += pause_times[i] * i;
- n += pause_times[i];
- if (i > mid)
- right += pause_times[i];
- while(right > left) {
- left += pause_times[mid++];
- right -= pause_times[mid];
- }
- }
- }
- erts_fprintf(file,"%lld\t%lld\t%ld\t",
- (long long)((max_global_minor_time > max_global_major_time ?
- max_global_minor_time :
- max_global_major_time)*1000),
- (n > 0 ? total_time / n : 0),
- mid);
-
- erts_fprintf(file,"\t%lld\t%lld\n",n,total_time);
-
- erts_fprintf(file,"\nMinor:\n");
- for (i = 0; i < MAX_PAUSE_TIME; i++) {
- if (i < 1000 || pause_times[i] > 0) {
- erts_fprintf(file,"%d\t%ld\n",i,pause_times[i]);
- }
- }
-
- fprintf(file,"Major:\n");
- for (i = 0; i < MAX_PAUSE_TIME; i++) {
- if (pause_times_old[i] > 0) {
- fprintf(file,"%d\t%ld\n",i,pause_times_old[i]);
- }
- }
-#endif /* BM_TIMERS */
-
-#ifdef BM_TIMERS
- total_time = 0; n = 0;
- left = 0; right = 0; mid = 0;
- fprintf(file,"\nLocal:\n");
- for (i = 0; i < MAX_PAUSE_TIME; i++) {
- if (local_pause_times[i] > 0) {
- erts_fprintf(file,"%d\t%ld\n",i,local_pause_times[i]);
- total_time += local_pause_times[i] * i;
- n += local_pause_times[i];
- if (i > mid)
- right += local_pause_times[i];
- while(right > left) {
- left += local_pause_times[mid++];
- right -= local_pause_times[mid];
- }
- }
- }
- erts_fprintf(file,"Mid: %ld Mean: %ld\n",(long)mid,
- (long)(n > 0 ? total_time / n : 0));
-#endif
-#endif /* 0 */
- fclose(file);
- }
- else
- fprintf(stderr,"Sorry... Can not write to %s!\n\r",BM_STATISTICS_FILE);
-#endif /* BM_STATISTICS */
-}
diff --git a/erts/emulator/beam/benchmark.h b/erts/emulator/beam/benchmark.h
deleted file mode 100644
index 0272896f4f..0000000000
--- a/erts/emulator/beam/benchmark.h
+++ /dev/null
@@ -1,295 +0,0 @@
-/*
- * %CopyrightBegin%
- *
- * Copyright Ericsson AB 2002-2016. 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 __BENCHMARK_H__
-#define __BENCHMARK_H__
-
-/* The define __BENCHMARK__ is the master switch to turn on and off
- * benchmarking. This will enable the benchmark-BIFs in hipe_bif1.c.
- * Documentation for the BIFs is in hipe_bif1.c, and that is where you
- * will find the information about how to accually get some data out
- * from these timers and counters.
- */
-/* #define __BENCHMARK__ */
-
-#ifdef __BENCHMARK__
-/*
- * The defines below enables different parts of the benchmaring.
- * Counters and timers that are disabled, always report zero in
- * the BIFs.
- */
-
-/* BM_TIMERS keeps track of the time spent in diferent parts of the
- * system. It only measures accual active time, not time spent in idle
- * mode. Currently, the Solaris hrtime_t will be used.
- * To add new timers look below.
- */
-#define BM_TIMERS
-
-/* BM_COUNTERS count all kinds of events that occurs in the system.
- * Among other things it counts the number of messages, then number of
- * garbage collections, the number of processes spawned etc.
- * To add new counters look below.
- */
-#define BM_COUNTERS
-
-/* BM_MESSAGE_SIZES keeps a log of the size of all messages sent in
- * the system. This introduce an overhead in time for the shared heap
- * system since all message sizes have to be calculated at send.
- */
-/* #define BM_MESSAGE_SIZES */
-
-/* BM_HEAP_SIZES goes through all processes at garbage collection time
- * to sum their allocated and used heap sizes. In anything else than a
- * shared heap system, this will cost.
- */
-/* #define BM_HEAP_SIZES */
-
-/* BM_STATISTICS saves an entry in the file BM_STATISTICS_FILE. This
- * is done for each erlang node at exit time.
- */
-/* #define BM_STATISTICS */
-
-#endif /* __BENCHMARK__ */
-
-
-#ifdef BM_STATISTICS
-# define BM_STATISTICS_FILE "/tmp/erlang_statistics.joppe.log"
-#endif /* BM_STATISTICS */
-
-
-/************ There are no more settings below this line *************/
-
-/*
- * Maintenance and how to add new stuff is documented by the code
- * below ;-)
- */
-
-#ifdef BM_COUNTERS
-/*********************************************************************
- * To add new counters:
- *
- * Add the variable here AND in benchmark.c. Use the macro
- * BM_COUNT(var) in the code where you want to increase it.
- *
- */
-extern unsigned long long processes_busy;
-extern unsigned long long processes_spawned;
-extern unsigned long long messages_sent;
-extern unsigned long long messages_copied;
-extern unsigned long long messages_ego;
-extern unsigned long long minor_gc;
-extern unsigned long long major_gc;
-
-#define BM_COUNT(var) (var)++;
-
-#define BM_EGO_COUNT(send,rec) { \
- if ((send) == (rec)) \
- BM_COUNT(messages_ego); }
-
-#define BM_LAZY_COPY_START long long gcs = minor_global_gc + major_global_gc;
-#define BM_LAZY_COPY_STOP { gcs = (minor_global_gc + major_global_gc) - gcs; \
- if (gcs > gc_in_copy) gc_in_copy = gcs; }
-
-#else /* !BM_COUNTERS */
-# define BM_COUNT(var)
-# define BM_EGO_COUNT(send,rec)
-# define BM_LAZY_COPY_START
-# define BM_LAZY_COPY_STOP
-#endif /* BM_COUNTERS */
-
-
-#ifdef BM_TIMERS
-/*********************************************************************
- * To add new timers:
- *
- * Add the variable below using the form extern BM_TIMER_T blah_time.
- * Also add them in benchmark.c using the macro NEW_TIMER(blah). Use
- * the macro BM_SWAP_TIMER(from,blah) ... BM_SWAP_TIMER(blah,to) to
- * start and stop the new timer. Note, that you have to know what
- * timer is running at the place where you want to insert your new
- * timer to be able to stop and start (from,to) it.
- *
- * You can use the macros BM_STOP_TIMER(blah) and BM_START_TIMER(blah)
- * around code that should not be timed at all. As above, you have to
- * know what timer to start and stop. The system timer is running at
- * most places in the emulator. Only the garbage collector and the
- * message sending has its own timers at the moment.
- *
- * The timer_time used when stopping timers is the time it takes to
- * start and stop the timers, calculated in init_benchmarking(). If it
- * is not there, the time it takes to do this will accually be
- * substantial compared to some small times in the system we want to
- * meassure (send time in shared heap for instance).
- */
-
-/* (Assuming Solaris) */
-
-#define BM_TIMER_T ErtsMonotonicTime
-#define BM_START_TIMER(t) system_clock = ERTS_MONOTONIC_TO_NSEC(erts_os_monotonic_time())
-#define BM_STOP_TIMER(t) do { \
- BM_TIMER_T tmp = (ERTS_MONOTONIC_TO_NSEC(erts_os_monotonic_time()) - system_clock) - timer_time; \
- t##_time += (tmp > 0 ? tmp : 0); \
-} while(0)
-
-#define BM_TIME_PRINTER(str,time) do { \
- int min,sec,milli,micro; \
- BM_TIMER_T tmp; \
- tmp = (time) / 1000; \
- micro = tmp % 1000; \
- tmp /= 1000; \
- milli = tmp % 1000; \
- tmp /= 1000; \
- sec = tmp % 60; \
- min = tmp / 60; \
- erts_fprintf(file,str": %d:%02d.%03d %03d\n",min,sec,milli,micro); \
-} while(0)
-
-extern BM_TIMER_T system_clock;
-
-extern BM_TIMER_T timer_time;
-extern BM_TIMER_T system_time;
-extern BM_TIMER_T gc_time;
-extern BM_TIMER_T minor_gc_time;
-extern BM_TIMER_T major_gc_time;
-extern BM_TIMER_T minor_global_gc_time;
-extern BM_TIMER_T major_global_gc_time;
-extern BM_TIMER_T send_time;
-extern BM_TIMER_T copy_time;
-extern BM_TIMER_T size_time;
-extern BM_TIMER_T max_minor_time;
-extern BM_TIMER_T max_major_time;
-extern BM_TIMER_T max_global_minor_time;
-extern BM_TIMER_T max_global_major_time;
-extern BM_TIMER_T misc0_time;
-extern BM_TIMER_T misc1_time;
-extern BM_TIMER_T misc2_time;
-
-#define MAX_PAUSE_TIME 500000
-extern unsigned long local_pause_times[MAX_PAUSE_TIME];
-extern unsigned long pause_times[MAX_PAUSE_TIME];
-extern unsigned long pause_times_old[MAX_PAUSE_TIME];
-
-#define MMU_INTERVAL 5 /* milli seconds */
-extern BM_TIMER_T mmu_counter;
-extern BM_TIMER_T mmu;
-
-#define BM_NEW_TIMER(t) BM_TIMER_T t##_time = 0;
-#define BM_RESET_TIMER(t) t##_time = 0;
-#define BM_SWAP_TIMER(t1,t2) do { BM_STOP_TIMER(t1); BM_START_TIMER(t2); } while(0)
-#define BM_MMU_INIT() do { \
- BM_TIMER_T gc = gc_time; \
- while (gc > 0) { \
- if (gc > MMU_INTERVAL) { \
- gc -= MMU_INTERVAL - mmu_counter; \
- erts_printf("%d\n",(int)((mmu / MMU_INTERVAL) * 100)); \
- mmu_counter = 0; mmu = 0; \
- } else { \
- mmu_counter += gc; \
- if (mmu_counter >= MMU_INTERVAL) { \
- mmu_counter -= MMU_INTERVAL; \
- erts_printf("%d\n",(int)((mmu / MMU_INTERVAL) * 100)); \
- mmu = 0; \
- } \
- gc = 0; \
- } \
- } \
- BM_RESET_TIMER(system); \
- BM_RESET_TIMER(send); \
- BM_RESET_TIMER(copy); \
- BM_RESET_TIMER(size); \
-} while(0)
-
-#define BM_MMU_READ() do { \
- BM_TIMER_T mut = system_time + send_time + copy_time + size_time; \
- while (mut > 0) { \
- if (mut > MMU_INTERVAL) { \
- BM_TIMER_T tmp = MMU_INTERVAL - mmu_counter; \
- mmu += tmp; mut -= tmp; \
- erts_printf("%d\n",(int)((mmu / MMU_INTERVAL) * 100)); \
- mmu_counter = 0; mmu = 0; \
- } else { \
- mmu_counter += mut; mmu += mut; \
- if (mmu_counter >= MMU_INTERVAL) { \
- mmu_counter -= MMU_INTERVAL; \
- mmu -= mmu_counter; \
- erts_printf("%d\n",(int)((mmu / MMU_INTERVAL) * 100)); \
- mmu = mmu_counter; \
- } \
- mut = 0; \
- } \
- } \
-} while(0)
-
-#else /* !BM_TIMERS */
-# define BM_NEW_TIMER(t)
-# define BM_START_TIMER(t)
-# define BM_STOP_TIMER(t)
-# define BM_RESET_TIMER(t)
-# define BM_SWAP_TIMER(t1,t2)
-# define BM_TIME_PRINTER(str,time)
-# define BM_MMU_INIT()
-# define BM_MMU_READ()
-#endif /* BM_TIMERS */
-
-#ifdef BM_HEAP_SIZES
-extern unsigned long long max_used_heap;
-extern unsigned long long max_allocated_heap;
-extern unsigned long long max_used_global_heap;
-extern unsigned long long max_allocated_global_heap;
-#endif /* BM_HEAP_SIZES */
-
-#ifdef BM_MESSAGE_SIZES
-extern unsigned long long words_sent;
-extern unsigned long long words_copied;
-extern unsigned long long words_prealloc;
-extern unsigned long long message_sizes[1000];
-
-#define BM_MESSAGE_COPIED(size) { \
- words_copied += size; \
- BM_COUNT(messages_copied); }
-
-#define BM_PREALLOC_DATA(size) { \
- words_prealloc += size; }
-
-#define BM_MESSAGE(mess,send,rec) { \
- Uint msize = size_object(mess); \
- words_sent += msize; \
- if (msize < 1000) \
- message_sizes[msize]++; \
- else \
- message_sizes[999]++; \
- BM_EGO_COUNT(send,rec); \
- BM_COUNT(messages_sent); }
-
-#else /* !BM_MESSAGE_SIZES */
-
-#define BM_MESSAGE_COPIED(size) BM_COUNT(messages_copied);
-#define BM_PREALLOC_DATA(size)
-#define BM_MESSAGE(mess,send,rec) { \
- BM_EGO_COUNT(send,rec); \
- BM_COUNT(messages_sent); }
-
-#endif /* BM_MESSAGE_SIZES */
-
-void init_benchmarking(void);
-void save_statistics(void);
-
-#endif /* _BENCHMARK_H_ */
diff --git a/erts/emulator/beam/big.h b/erts/emulator/beam/big.h
index 464acd67f6..4a96d971c3 100644
--- a/erts/emulator/beam/big.h
+++ b/erts/emulator/beam/big.h
@@ -21,17 +21,8 @@
#ifndef __BIG_H__
#define __BIG_H__
-#ifndef __SYS_H__
#include "sys.h"
-#endif
-
-#ifndef __CONFIG_H__
-#include "erl_vm.h"
-#endif
-
-#ifndef __GLOBAL_H__
#include "global.h"
-#endif
typedef Uint ErtsDigit;
diff --git a/erts/emulator/beam/erl_gc.c b/erts/emulator/beam/erl_gc.c
index d0d74bbf44..a224383493 100644
--- a/erts/emulator/beam/erl_gc.c
+++ b/erts/emulator/beam/erl_gc.c
@@ -672,6 +672,7 @@ do_major_collection:
killed before a GC could be done. */
if (reds == -2) {
ErtsProcLocks locks = ERTS_PROC_LOCKS_ALL;
+ int res;
erts_smp_proc_lock(p, ERTS_PROC_LOCKS_ALL_MINOR);
erts_send_exit_signal(p, p->common.id, p, &locks,
@@ -683,7 +684,9 @@ do_major_collection:
erts_smp_atomic32_read_band_nob(&p->state, ~ERTS_PSFLG_GC);
/* We have to make sure that we have space for need on the heap */
- return delay_garbage_collection(p, live_hf_end, need, fcalls);
+ res = delay_garbage_collection(p, live_hf_end, need, fcalls);
+ ERTS_MSACC_POP_STATE_M();
+ return res;
}
erts_smp_atomic32_read_band_nob(&p->state, ~ERTS_PSFLG_GC);
diff --git a/erts/emulator/beam/erl_init.c b/erts/emulator/beam/erl_init.c
index fbdafec4ef..2239b6f045 100644
--- a/erts/emulator/beam/erl_init.c
+++ b/erts/emulator/beam/erl_init.c
@@ -332,8 +332,6 @@ erl_init(int ncpu,
int node_tab_delete_delay,
ErtsDbSpinCount db_spin_count)
{
- init_benchmarking();
-
erts_bif_unique_init();
erts_init_monitors();
erts_init_time(time_correction, time_warp_mode);
@@ -2345,8 +2343,6 @@ erts_exit_vv(int n, int flush_async, char *fmt, va_list args1, va_list args2)
{
system_cleanup(flush_async);
- save_statistics();
-
if (erts_mtrace_enabled)
erts_mtrace_exit((Uint32) n);
diff --git a/erts/emulator/beam/erl_map.c b/erts/emulator/beam/erl_map.c
index 8efc983f04..979a0040b0 100644
--- a/erts/emulator/beam/erl_map.c
+++ b/erts/emulator/beam/erl_map.c
@@ -497,18 +497,50 @@ Eterm erts_hashmap_from_array(ErtsHeapFactory* factory, Eterm *leafs, Uint n,
return res;
}
+Eterm erts_map_from_ks_and_vs(ErtsHeapFactory *factory, Eterm *ks0, Eterm *vs0, Uint n)
+{
+ if (n < MAP_SMALL_MAP_LIMIT) {
+ Eterm *ks, *vs, *hp;
+ flatmap_t *mp;
+ Eterm keys;
-Eterm erts_hashmap_from_ks_and_vs_extra(Process *p, Eterm *ks, Eterm *vs, Uint n,
+ hp = erts_produce_heap(factory, 3 + 1 + (2 * n), 0);
+ keys = make_tuple(hp);
+ *hp++ = make_arityval(n);
+ ks = hp;
+ hp += n;
+ mp = (flatmap_t*)hp;
+ hp += MAP_HEADER_FLATMAP_SZ;
+ vs = hp;
+
+ mp->thing_word = MAP_HEADER_FLATMAP;
+ mp->size = n;
+ mp->keys = keys;
+
+ sys_memcpy(ks, ks0, n * sizeof(Eterm));
+ sys_memcpy(vs, vs0, n * sizeof(Eterm));
+
+ erts_validate_and_sort_flatmap(mp);
+
+ return make_flatmap(mp);
+ } else {
+ return erts_hashmap_from_ks_and_vs(factory, ks0, vs0, n);
+ }
+ return THE_NON_VALUE;
+}
+
+
+Eterm erts_hashmap_from_ks_and_vs_extra(ErtsHeapFactory *factory,
+ Eterm *ks, Eterm *vs, Uint n,
Eterm key, Eterm value) {
Uint32 sw, hx;
Uint i,sz;
hxnode_t *hxns;
- ErtsHeapFactory factory;
Eterm *hp, res;
sz = (key == THE_NON_VALUE) ? n : (n + 1);
ASSERT(sz > MAP_SMALL_MAP_LIMIT);
- hp = HAlloc(p, 2 * sz);
+ hp = erts_produce_heap(factory, 2 * sz, 0);
/* create tmp hx values and leaf ptrs */
hxns = (hxnode_t *)erts_alloc(ERTS_ALC_T_TMP, sz * sizeof(hxnode_t));
@@ -531,12 +563,9 @@ Eterm erts_hashmap_from_ks_and_vs_extra(Process *p, Eterm *ks, Eterm *vs, Uint n
hxns[i].i = i;
}
- erts_factory_proc_init(&factory, p);
- res = hashmap_from_unsorted_array(&factory, hxns, sz, 0);
- erts_factory_close(&factory);
+ res = hashmap_from_unsorted_array(factory, hxns, sz, 0);
erts_free(ERTS_ALC_T_TMP, (void *) hxns);
- ERTS_VERIFY_UNUSED_TEMP_ALLOC(p);
return res;
}
@@ -1780,11 +1809,14 @@ Eterm erts_maps_put(Process *p, Eterm key, Eterm value, Eterm map) {
/* the map will grow */
if (n >= MAP_SMALL_MAP_LIMIT) {
+ ErtsHeapFactory factory;
HRelease(p, shp + MAP_HEADER_FLATMAP_SZ + n, shp);
ks = flatmap_get_keys(mp);
vs = flatmap_get_values(mp);
- res = erts_hashmap_from_ks_and_vs_extra(p,ks,vs,n,key,value);
+ erts_factory_proc_init(&factory, p);
+ res = erts_hashmap_from_ks_and_vs_extra(&factory,ks,vs,n,key,value);
+ erts_factory_close(&factory);
return res;
}
diff --git a/erts/emulator/beam/erl_map.h b/erts/emulator/beam/erl_map.h
index 8b5c9582ba..61a841f7f0 100644
--- a/erts/emulator/beam/erl_map.h
+++ b/erts/emulator/beam/erl_map.h
@@ -98,10 +98,12 @@ Eterm* hashmap_iterator_prev(struct ErtsWStack_* s);
int hashmap_key_hash_cmp(Eterm* ap, Eterm* bp);
Eterm erts_hashmap_from_array(ErtsHeapFactory*, Eterm *leafs, Uint n, int reject_dupkeys);
-#define erts_hashmap_from_ks_and_vs(P, KS, VS, N) \
- erts_hashmap_from_ks_and_vs_extra((P), (KS), (VS), (N), THE_NON_VALUE, THE_NON_VALUE);
+#define erts_hashmap_from_ks_and_vs(F, KS, VS, N) \
+ erts_hashmap_from_ks_and_vs_extra((F), (KS), (VS), (N), THE_NON_VALUE, THE_NON_VALUE);
-Eterm erts_hashmap_from_ks_and_vs_extra(Process *p, Eterm *ks, Eterm *vs, Uint n,
+Eterm erts_map_from_ks_and_vs(ErtsHeapFactory *factory, Eterm *ks, Eterm *vs, Uint n);
+Eterm erts_hashmap_from_ks_and_vs_extra(ErtsHeapFactory *factory,
+ Eterm *ks, Eterm *vs, Uint n,
Eterm k, Eterm v);
const Eterm *erts_maps_get(Eterm key, Eterm map);
diff --git a/erts/emulator/beam/erl_message.c b/erts/emulator/beam/erl_message.c
index 71ab92937d..91e06cde2d 100644
--- a/erts/emulator/beam/erl_message.c
+++ b/erts/emulator/beam/erl_message.c
@@ -697,9 +697,6 @@ erts_send_message(Process* sender,
#ifdef SHCOPY_SEND
erts_shcopy_t info;
#endif
- BM_STOP_TIMER(system);
- BM_MESSAGE(message,sender,receiver);
- BM_START_TIMER(send);
#ifdef USE_VM_PROBES
*sender_name = *receiver_name = '\0';
@@ -720,7 +717,6 @@ erts_send_message(Process* sender,
#ifdef USE_VM_PROBES
Uint dt_utag_size = 0;
#endif
- BM_SWAP_TIMER(send,size);
/* SHCOPY corrupts the heap between
* copy_shared_calculate, and
@@ -747,8 +743,6 @@ erts_send_message(Process* sender,
#else
msize = size_object(message);
#endif
- BM_SWAP_TIMER(size,send);
-
mp = erts_alloc_message_heap_state(receiver,
&receiver_state,
receiver_locks,
@@ -760,8 +754,6 @@ erts_send_message(Process* sender,
&hp,
&ohp);
- BM_SWAP_TIMER(send,copy);
-
#ifdef SHCOPY_SEND
if (is_not_immed(message))
message = copy_shared_perform(message, msize, &info, &hp, ohp);
@@ -792,9 +784,6 @@ erts_send_message(Process* sender,
msize, tok_label, tok_lastcnt, tok_serial);
}
#endif
- BM_MESSAGE_COPIED(msize);
- BM_SWAP_TIMER(copy,send);
-
} else {
Eterm *hp;
@@ -803,22 +792,18 @@ erts_send_message(Process* sender,
msize = 0;
}
else {
- BM_SWAP_TIMER(send,size);
#ifdef SHCOPY_SEND
INITIALIZE_SHCOPY(info);
msize = copy_shared_calculate(message, &info);
#else
msize = size_object(message);
#endif
- BM_SWAP_TIMER(size,send);
-
mp = erts_alloc_message_heap_state(receiver,
&receiver_state,
receiver_locks,
msize,
&hp,
&ohp);
- BM_SWAP_TIMER(send,copy);
#ifdef SHCOPY_SEND
if (is_not_immed(message))
message = copy_shared_perform(message, msize, &info, &hp, ohp);
@@ -827,8 +812,6 @@ erts_send_message(Process* sender,
if (is_not_immed(message))
message = copy_struct(message, msize, &hp, ohp);
#endif
- BM_MESSAGE_COPIED(msz);
- BM_SWAP_TIMER(copy,send);
}
#ifdef USE_VM_PROBES
DTRACE6(message_send, sender_name, receiver_name,
@@ -846,8 +829,6 @@ erts_send_message(Process* sender,
mp, message,
sender->common.id);
- BM_SWAP_TIMER(send,system);
-
return res;
}
diff --git a/erts/emulator/beam/erl_msacc.c b/erts/emulator/beam/erl_msacc.c
index 544bc8b983..421445fbad 100644
--- a/erts/emulator/beam/erl_msacc.c
+++ b/erts/emulator/beam/erl_msacc.c
@@ -40,10 +40,11 @@
#include "erl_bif_unique.h"
#include "erl_map.h"
#include "erl_msacc.h"
+#include "erl_bif_table.h"
#if ERTS_ENABLE_MSACC
-static Eterm erts_msacc_gather_stats(ErtsMsAcc *msacc, Eterm **hpp, Uint *szp);
+static Eterm erts_msacc_gather_stats(ErtsMsAcc *msacc, ErtsHeapFactory *factory);
static void erts_msacc_reset(ErtsMsAcc *msacc);
static ErtsMsAcc* get_msacc(void);
@@ -52,7 +53,9 @@ erts_tsd_key_t ERTS_WRITE_UNLIKELY(erts_msacc_key);
#else
ErtsMsAcc *ERTS_WRITE_UNLIKELY(erts_msacc) = NULL;
#endif
+#ifndef ERTS_MSACC_ALWAYS_ON
int ERTS_WRITE_UNLIKELY(erts_msacc_enabled);
+#endif
static Eterm *erts_msacc_state_atoms = NULL;
static erts_rwmtx_t msacc_mutex;
@@ -62,6 +65,12 @@ static ErtsMsAcc *msacc_unmanaged = NULL;
static Uint msacc_unmanaged_count = 0;
#endif
+#if ERTS_MSACC_STATE_COUNT < MAP_SMALL_MAP_LIMIT
+#define DEFAULT_MSACC_MSG_SIZE (3 + 1 + ERTS_MSACC_STATE_COUNT * 2 + 3 + REF_THING_SIZE)
+#else
+#define DEFAULT_MSACC_MSG_SIZE (3 + ERTS_MSACC_STATE_COUNT * 3 + 3 + REF_THING_SIZE)
+#endif
+
/* we have to split initiation as atoms are not inited in early init */
void erts_msacc_early_init(void) {
#ifndef ERTS_MSACC_ALWAYS_ON
@@ -88,7 +97,8 @@ void erts_msacc_init(void) {
void erts_msacc_init_thread(char *type, int id, int managed) {
ErtsMsAcc *msacc;
- msacc = erts_alloc(ERTS_ALC_T_MSACC, sizeof(ErtsMsAcc));
+ msacc = erts_alloc(ERTS_ALC_T_MSACC, sizeof(ErtsMsAcc) +
+ sizeof(ErtsMsAccPerfCntr) * ERTS_MSACC_STATE_COUNT);
msacc->type = strdup(type);
msacc->id = make_small(id);
@@ -122,79 +132,80 @@ void erts_msacc_init_thread(char *type, int id, int managed) {
#endif
}
+#ifdef ERTS_MSACC_EXTENDED_STATES
+
+void erts_msacc_set_bif_state(ErtsMsAcc *__erts_msacc_cache, Eterm mod, void *fn) {
+
+#ifdef ERTS_MSACC_EXTENDED_BIFS
+#define BIF_LIST(Mod,Func,Arity,FuncAddr,Num) \
+ if (fn == &FuncAddr) { \
+ ERTS_MSACC_SET_STATE_CACHED_M_X(ERTS_MSACC_STATIC_STATE_COUNT + Num); \
+ } else
+#include "erl_bif_list.h"
+#undef BIF_LIST
+ { /* The last else in the macro expansion,
+ this happens for internal bifs, i.e. traps etc */
+ ERTS_MSACC_SET_STATE_CACHED_M_X(ERTS_MSACC_STATE_BIF);
+ }
+#else
+ if (mod == am_ets) {
+ ERTS_MSACC_SET_STATE_CACHED_M_X(ERTS_MSACC_STATE_ETS);
+ } else {
+ ERTS_MSACC_SET_STATE_CACHED_M_X(ERTS_MSACC_STATE_BIF);
+ }
+#endif
+}
+
+#endif
+
/*
* Creates a structure looking like this
* #{ type => scheduler, id => 1, counters => #{ State1 => Counter1 ... StateN => CounterN}}
*/
static
-Eterm erts_msacc_gather_stats(ErtsMsAcc *msacc, Eterm **hpp, Uint *szp) {
+Eterm erts_msacc_gather_stats(ErtsMsAcc *msacc, ErtsHeapFactory *factory) {
+ Uint sz = 0;
+ Eterm *hp, cvs[ERTS_MSACC_STATE_COUNT];
+ Eterm key, state_map;
int i;
- Eterm *hp;
- Eterm key, state_key, state_map;
- Eterm res = THE_NON_VALUE;
- flatmap_t *map;
-
- if (szp) {
- *szp += MAP_HEADER_FLATMAP_SZ + 1 + 2*(3);
- *szp += MAP_HEADER_FLATMAP_SZ + 1 + 2*(ERTS_MSACC_STATE_COUNT);
- for (i = 0; i < ERTS_MSACC_STATE_COUNT; i++) {
- (void)erts_bld_sint64(NULL,szp,(Sint64)msacc->perf_counters[i]);
+ flatmap_t *map;
+
+ hp = erts_produce_heap(factory, 4, 0);
+ key = TUPLE3(hp,am_counters,am_id,am_type);
+
+ for (i = 0; i < ERTS_MSACC_STATE_COUNT; i++) {
+ cvs[i] = erts_bld_sint64(NULL, &sz,(Sint64)msacc->counters[i].pc);
#ifdef ERTS_MSACC_STATE_COUNTERS
- (void)erts_bld_uint64(NULL,szp,msacc->state_counters[i]);
- *szp += 3; /* tuple to put state+perf counter in */
+ erts_bld_uint64(NULL,&sz,msacc->counters[i].sc);
+ sz += 3;
#endif
- }
}
- if (hpp) {
- Eterm counters[ERTS_MSACC_STATE_COUNT];
- hp = *hpp;
- for (i = 0; i < ERTS_MSACC_STATE_COUNT; i++) {
- Eterm counter = erts_bld_sint64(&hp,NULL,(Sint64)msacc->perf_counters[i]);
+ hp = erts_produce_heap(factory, sz, 0);
+
+ for (i = 0; i < ERTS_MSACC_STATE_COUNT; i++) {
+ cvs[i] = erts_bld_sint64(&hp,NULL,(Sint64)msacc->counters[i].pc);
#ifdef ERTS_MSACC_STATE_COUNTERS
- Eterm counter__ = erts_bld_uint64(&hp,NULL,msacc->state_counters[i]);
- counters[i] = TUPLE2(hp,counter,counter__);
- hp += 3;
-#else
- counters[i] = counter;
+ Eterm counter__ = erts_bld_uint64(&hp,NULL,msacc->counters[i].sc);
+ cvs[i] = TUPLE2(hp,cvs[i],counter__);
+ hp += 3;
#endif
- }
-
- key = TUPLE3(hp,am_counters,am_id,am_type);
- hp += 4;
-
- state_key = make_tuple(hp);
- hp[0] = make_arityval(ERTS_MSACC_STATE_COUNT);
-
- for (i = 0; i < ERTS_MSACC_STATE_COUNT; i++)
- hp[1+i] = erts_msacc_state_atoms[i];
- hp += 1 + ERTS_MSACC_STATE_COUNT;
-
- map = (flatmap_t*)hp;
- hp += MAP_HEADER_FLATMAP_SZ;
- map->thing_word = MAP_HEADER_FLATMAP;
- map->size = ERTS_MSACC_STATE_COUNT;
- map->keys = state_key;
- for (i = 0; i < ERTS_MSACC_STATE_COUNT; i++)
- hp[i] = counters[i];
- hp += ERTS_MSACC_STATE_COUNT;
- state_map = make_flatmap(map);
-
- map = (flatmap_t*)hp;
- hp += MAP_HEADER_FLATMAP_SZ;
- map->thing_word = MAP_HEADER_FLATMAP;
- map->size = 3;
- map->keys = key;
- hp[0] = state_map;
- hp[1] = msacc->id;
- hp[2] = am_atom_put(msacc->type,strlen(msacc->type));
- hp += 3;
-
- *hpp = hp;
- res = make_flatmap(map);
}
- return res;
+ state_map = erts_map_from_ks_and_vs(factory, erts_msacc_state_atoms, cvs,
+ ERTS_MSACC_STATE_COUNT);
+
+ hp = erts_produce_heap(factory, MAP_HEADER_FLATMAP_SZ + 3, 0);
+ map = (flatmap_t*)hp;
+ hp += MAP_HEADER_FLATMAP_SZ;
+ map->thing_word = MAP_HEADER_FLATMAP;
+ map->size = 3;
+ map->keys = key;
+ hp[0] = state_map;
+ hp[1] = msacc->id;
+ hp[2] = am_atom_put(msacc->type,strlen(msacc->type));
+
+ return make_flatmap(map);
}
typedef struct {
@@ -222,40 +233,31 @@ static void send_reply(ErtsMsAcc *msacc, ErtsMSAccReq *msaccrp) {
ErtsSchedulerData *esdp = erts_get_scheduler_data();
Process *rp = msaccrp->proc;
ErtsMessage *msgp = NULL;
- Eterm **hpp, *hp;
+ Eterm *hp;
Eterm ref_copy = NIL, msg;
- Uint sz, *szp;
- ErlOffHeap *ohp = NULL;
ErtsProcLocks rp_locks = (esdp && msaccrp->req_sched == esdp->no
? ERTS_PROC_LOCK_MAIN : 0);
+ ErtsHeapFactory factory;
- sz = 0;
- hpp = NULL;
- szp = &sz;
-
- if (msacc->unmanaged) erts_mtx_lock(&msacc->mtx);
-
- while (1) {
- if (hpp)
- ref_copy = STORE_NC(hpp, ohp, msaccrp->ref);
- else
- *szp += REF_THING_SIZE;
-
- if (msaccrp->action != ERTS_MSACC_GATHER)
- msg = ref_copy;
- else {
- msg = erts_msacc_gather_stats(msacc, hpp, szp);
- msg = erts_bld_tuple(hpp, szp, 2, ref_copy, msg);
- }
- if (hpp)
- break;
-
- msgp = erts_alloc_message_heap(rp, &rp_locks, sz, &hp, &ohp);
- hpp = &hp;
- szp = NULL;
- }
+ if (msaccrp->action == ERTS_MSACC_GATHER) {
+
+ msgp = erts_factory_message_create(&factory, rp, &rp_locks, DEFAULT_MSACC_MSG_SIZE);
+
+ if (msacc->unmanaged) erts_mtx_lock(&msacc->mtx);
- if (msacc->unmanaged) erts_mtx_unlock(&msacc->mtx);
+ hp = erts_produce_heap(&factory, REF_THING_SIZE + 3 /* tuple */, 0);
+ ref_copy = STORE_NC(&hp, &msgp->hfrag.off_heap, msaccrp->ref);
+ msg = erts_msacc_gather_stats(msacc, &factory);
+ msg = TUPLE2(hp, ref_copy, msg);
+
+ if (msacc->unmanaged) erts_mtx_unlock(&msacc->mtx);
+
+ erts_factory_close(&factory);
+ } else {
+ ErlOffHeap *ohp = NULL;
+ msgp = erts_alloc_message_heap(rp, &rp_locks, REF_THING_SIZE, &hp, &ohp);
+ msg = STORE_NC(&hp, &msgp->hfrag.off_heap, msaccrp->ref);
+ }
erts_queue_message(rp, rp_locks, msgp, msg, am_system);
@@ -308,9 +310,9 @@ static void erts_msacc_reset(ErtsMsAcc *msacc) {
if (msacc->unmanaged) erts_mtx_lock(&msacc->mtx);
for (i = 0; i < ERTS_MSACC_STATE_COUNT; i++) {
- msacc->perf_counters[i] = 0;
+ msacc->counters[i].pc = 0;
#ifdef ERTS_MSACC_STATE_COUNTERS
- msacc->state_counters[i] = 0;
+ msacc->counters[i].sc = 0;
#endif
}
@@ -415,7 +417,7 @@ erts_msacc_request(Process *c_p, int action, Eterm *threads)
ErtsSysPerfCounter perf_counter;
/* if enabled update stats */
perf_counter = erts_sys_perf_counter();
- unmanaged[i]->perf_counters[unmanaged[i]->state] +=
+ unmanaged[i]->counters[unmanaged[i]->state].pc +=
perf_counter - unmanaged[i]->perf_counter;
unmanaged[i]->perf_counter = perf_counter;
}
@@ -454,7 +456,7 @@ erts_msacc_request(Process *c_p, int action, Eterm *threads)
for (msacc = msacc_unmanaged; msacc != NULL; msacc = msacc->next) {
erts_mtx_lock(&msacc->mtx);
perf_counter = erts_sys_perf_counter();
- msacc->perf_counters[msacc->state] += perf_counter - msacc->perf_counter;
+ msacc->counters[msacc->state].pc += perf_counter - msacc->perf_counter;
msacc->perf_counter = 0;
erts_mtx_unlock(&msacc->mtx);
}
diff --git a/erts/emulator/beam/erl_msacc.h b/erts/emulator/beam/erl_msacc.h
index 284388f7aa..ad7c8c5eee 100644
--- a/erts/emulator/beam/erl_msacc.h
+++ b/erts/emulator/beam/erl_msacc.h
@@ -35,6 +35,10 @@
this reduces overhead a little bit when profiling */
/* #define ERTS_MSACC_ALWAYS_ON 1 */
+/* Uncomment this to keep individual stats for all
+ of the bifs when extended states is enabled */
+/* #define ERTS_MSACC_EXTENDED_BIFS 1 */
+
#define ERTS_MSACC_DISABLE 0
#define ERTS_MSACC_ENABLE 1
#define ERTS_MSACC_RESET 2
@@ -92,7 +96,13 @@ static char *erts_msacc_states[] = {
#define ERTS_MSACC_STATE_SLEEP 13
#define ERTS_MSACC_STATE_TIMERS 14
-#define ERTS_MSACC_STATE_COUNT 15
+#define ERTS_MSACC_STATIC_STATE_COUNT 15
+
+#ifdef ERTS_MSACC_EXTENDED_BIFS
+#define ERTS_MSACC_STATE_COUNT (ERTS_MSACC_STATIC_STATE_COUNT + BIF_SIZE)
+#else
+#define ERTS_MSACC_STATE_COUNT ERTS_MSACC_STATIC_STATE_COUNT
+#endif
#if ERTS_MSACC_STATE_STRINGS
static char *erts_msacc_states[] = {
@@ -111,22 +121,26 @@ static char *erts_msacc_states[] = {
"send",
"sleep",
"timers"
+#ifdef ERTS_MSACC_EXTENDED_BIFS
+#define BIF_LIST(Mod,Func,Arity,FuncAddr,Num) \
+ ,"bif_" #Mod "_" #Func "_" #Arity
+#include "erl_bif_list.h"
+#undef BIF_LIST
+#endif
};
#endif
#endif
typedef struct erl_msacc_t_ ErtsMsAcc;
-
-struct erl_msacc_t_ {
-
- /* the the values below are protected by mtx iff unmanaged = 1 */
- ErtsSysPerfCounter perf_counter;
- ErtsSysPerfCounter perf_counters[ERTS_MSACC_STATE_COUNT];
+typedef struct erl_msacc_p_cnt_t_ {
+ ErtsSysPerfCounter pc;
#ifdef ERTS_MSACC_STATE_COUNTERS
- Uint64 state_counters[ERTS_MSACC_STATE_COUNT];
+ Uint64 sc;
#endif
- Uint state;
+} ErtsMsAccPerfCntr;
+
+struct erl_msacc_t_ {
/* protected by msacc_mutex in erl_msacc.c, and should be constant */
int unmanaged;
@@ -135,12 +149,16 @@ struct erl_msacc_t_ {
erts_tid_t tid;
Eterm id;
char *type;
+
+ /* the the values below are protected by mtx iff unmanaged = 1 */
+ ErtsSysPerfCounter perf_counter;
+ Uint state;
+ ErtsMsAccPerfCntr counters[];
+
};
#if ERTS_ENABLE_MSACC
-#define ERTS_MSACC_INLINE ERTS_GLB_INLINE
-
#ifdef USE_THREADS
extern erts_tsd_key_t erts_msacc_key;
#else
@@ -276,20 +294,20 @@ void erts_msacc_init_thread(char *type, int id, int liberty);
#define ERTS_MSACC_PUSH_AND_SET_STATE_M(state) \
ERTS_MSACC_PUSH_STATE_M(); ERTS_MSACC_SET_STATE_CACHED_M(state)
-ERTS_MSACC_INLINE
+ERTS_GLB_INLINE
void erts_msacc_set_state_um__(ErtsMsAcc *msacc,Uint state,int increment);
-ERTS_MSACC_INLINE
+ERTS_GLB_INLINE
void erts_msacc_set_state_m__(ErtsMsAcc *msacc,Uint state,int increment);
-ERTS_MSACC_INLINE
+ERTS_GLB_INLINE
Uint erts_msacc_get_state_um__(ErtsMsAcc *msacc);
-ERTS_MSACC_INLINE
+ERTS_GLB_INLINE
Uint erts_msacc_get_state_m__(ErtsMsAcc *msacc);
#if ERTS_GLB_INLINE_INCL_FUNC_DEF
-ERTS_MSACC_INLINE
+ERTS_GLB_INLINE
Uint erts_msacc_get_state_um__(ErtsMsAcc *msacc) {
Uint state;
if (msacc->unmanaged)
@@ -300,12 +318,12 @@ Uint erts_msacc_get_state_um__(ErtsMsAcc *msacc) {
return state;
}
-ERTS_MSACC_INLINE
+ERTS_GLB_INLINE
Uint erts_msacc_get_state_m__(ErtsMsAcc *msacc) {
return msacc->state;
}
-ERTS_MSACC_INLINE
+ERTS_GLB_INLINE
void erts_msacc_set_state_um__(ErtsMsAcc *msacc, Uint new_state, int increment) {
if (ERTS_UNLIKELY(msacc->unmanaged)) {
erts_mtx_lock(&msacc->mtx);
@@ -322,7 +340,7 @@ void erts_msacc_set_state_um__(ErtsMsAcc *msacc, Uint new_state, int increment)
erts_mtx_unlock(&msacc->mtx);
}
-ERTS_MSACC_INLINE
+ERTS_GLB_INLINE
void erts_msacc_set_state_m__(ErtsMsAcc *msacc, Uint new_state, int increment) {
ErtsSysPerfCounter prev_perf_counter;
Sint64 diff;
@@ -334,9 +352,9 @@ void erts_msacc_set_state_m__(ErtsMsAcc *msacc, Uint new_state, int increment) {
msacc->perf_counter = erts_sys_perf_counter();
diff = msacc->perf_counter - prev_perf_counter;
ASSERT(diff >= 0);
- msacc->perf_counters[msacc->state] += diff;
+ msacc->counters[msacc->state].pc += diff;
#ifdef ERTS_MSACC_STATE_COUNTERS
- msacc->state_counters[new_state] += increment;
+ msacc->counters[new_state].sc += increment;
#endif
msacc->state = new_state;
}
@@ -364,7 +382,7 @@ void erts_msacc_set_state_m__(ErtsMsAcc *msacc, Uint new_state, int increment) {
#define ERTS_MSACC_SET_STATE_CACHED_M(state)
#define ERTS_MSACC_POP_STATE_M()
#define ERTS_MSACC_PUSH_AND_SET_STATE_M(state)
-
+#define ERTS_MSACC_SET_BIF_STATE_CACHED_X(Mod,Addr)
#endif /* ERTS_ENABLE_MSACC */
@@ -385,9 +403,13 @@ void erts_msacc_set_state_m__(ErtsMsAcc *msacc, Uint new_state, int increment) {
#define ERTS_MSACC_SET_STATE_CACHED_M_X(state)
#define ERTS_MSACC_POP_STATE_M_X()
#define ERTS_MSACC_PUSH_AND_SET_STATE_M_X(state)
+#define ERTS_MSACC_PUSH_AND_SET_STATE_CACHED_M_X(state)
+#define ERTS_MSACC_SET_BIF_STATE_CACHED_X(Mod,Addr)
#else
+void erts_msacc_set_bif_state(ErtsMsAcc *msacc, Eterm mod, void *addr);
+
#define ERTS_MSACC_PUSH_STATE_X() ERTS_MSACC_PUSH_STATE()
#define ERTS_MSACC_POP_STATE_X() ERTS_MSACC_POP_STATE()
#define ERTS_MSACC_SET_STATE_X(state) ERTS_MSACC_SET_STATE(state)
@@ -403,6 +425,9 @@ void erts_msacc_set_state_m__(ErtsMsAcc *msacc, Uint new_state, int increment) {
#define ERTS_MSACC_SET_STATE_CACHED_M_X(state) ERTS_MSACC_SET_STATE_CACHED_M(state)
#define ERTS_MSACC_POP_STATE_M_X() ERTS_MSACC_POP_STATE_M()
#define ERTS_MSACC_PUSH_AND_SET_STATE_M_X(state) ERTS_MSACC_PUSH_AND_SET_STATE_M(state)
+#define ERTS_MSACC_SET_BIF_STATE_CACHED_X(Mod,Addr) \
+ if (ERTS_MSACC_IS_ENABLED_CACHED_X()) \
+ erts_msacc_set_bif_state(__erts_msacc_cache, Mod, Addr)
#endif /* !ERTS_MSACC_EXTENDED_STATES */
diff --git a/erts/emulator/beam/erl_nif.c b/erts/emulator/beam/erl_nif.c
index 23931f0e54..c6127a4967 100644
--- a/erts/emulator/beam/erl_nif.c
+++ b/erts/emulator/beam/erl_nif.c
@@ -3502,6 +3502,7 @@ Eterm erts_nif_call_function(Process *p, Process *tracee,
struct enif_environment_t env;
ErlHeapFragment *orig_hf = MBUF(p);
ErlOffHeap orig_oh = MSO(p);
+ Eterm *orig_htop = HEAP_TOP(p);
ASSERT(is_internal_pid(p->common.id));
MBUF(p) = NULL;
clear_offheap(&MSO(p));
@@ -3523,6 +3524,7 @@ Eterm erts_nif_call_function(Process *p, Process *tracee,
/* restore original heap fragment list */
MBUF(p) = orig_hf;
MSO(p) = orig_oh;
+ HEAP_TOP(p) = orig_htop;
} else {
/* Nif call was done without a process context,
so we create a phony one. */
diff --git a/erts/emulator/beam/erl_process.c b/erts/emulator/beam/erl_process.c
index 66f22979ad..b5d8c5bc75 100644
--- a/erts/emulator/beam/erl_process.c
+++ b/erts/emulator/beam/erl_process.c
@@ -8177,6 +8177,8 @@ sched_dirty_cpu_thread_func(void *vesdp)
esdp->thr_id += erts_no_schedulers;
+ erts_msacc_init_thread("dirty_cpu_scheduler", no, 0);
+
erts_thr_progress_register_unmanaged_thread(&callbacks);
#ifdef ERTS_ENABLE_LOCK_CHECK
{
@@ -8222,6 +8224,8 @@ sched_dirty_io_thread_func(void *vesdp)
esdp->thr_id += erts_no_schedulers + erts_no_dirty_cpu_schedulers;
+ erts_msacc_init_thread("dirty_io_scheduler", no, 0);
+
erts_thr_progress_register_unmanaged_thread(&callbacks);
#ifdef ERTS_ENABLE_LOCK_CHECK
{
@@ -9588,8 +9592,6 @@ Process *erts_schedule(ErtsSchedulerData *esdp, Process *p, int calls)
erts_smp_runq_lock(rq);
}
}
- BM_STOP_TIMER(system);
-
}
ERTS_SMP_LC_ASSERT(!is_normal_sched || !erts_thr_progress_is_blocking());
@@ -9825,10 +9827,6 @@ Process *erts_schedule(ErtsSchedulerData *esdp, Process *p, int calls)
goto check_activities_to_run;
}
- ERTS_MSACC_SET_STATE_CACHED_M(ERTS_MSACC_STATE_EMULATOR);
-
- BM_START_TIMER(system);
-
/*
* Take the chosen process out of the queue.
*/
@@ -9934,6 +9932,8 @@ Process *erts_schedule(ErtsSchedulerData *esdp, Process *p, int calls)
}
+ ERTS_MSACC_SET_STATE_CACHED_M(ERTS_MSACC_STATE_EMULATOR);
+
#ifdef ERTS_SMP
if (flags & ERTS_RUNQ_FLG_PROTECTED)
@@ -11154,18 +11154,11 @@ erl_create_process(Process* parent, /* Parent of process (default group leader).
|| (erts_smp_atomic32_read_nob(&p->state)
& ERTS_PSFLG_OFF_HEAP_MSGQ));
-#ifdef BM_COUNTERS
- processes_busy++;
-#endif
- BM_COUNT(processes_spawned);
-
- BM_SWAP_TIMER(system,size);
#ifdef SHCOPY_SPAWN
arg_size = copy_shared_calculate(args, &info);
#else
arg_size = size_object(args);
#endif
- BM_SWAP_TIMER(size,system);
heap_need = arg_size;
p->flags = flags;
@@ -11242,18 +11235,12 @@ erl_create_process(Process* parent, /* Parent of process (default group leader).
p->max_arg_reg = sizeof(p->def_arg_reg)/sizeof(p->def_arg_reg[0]);
p->arg_reg[0] = mod;
p->arg_reg[1] = func;
- BM_STOP_TIMER(system);
- BM_MESSAGE(args,p,parent);
- BM_START_TIMER(system);
- BM_SWAP_TIMER(system,copy);
#ifdef SHCOPY_SPAWN
p->arg_reg[2] = copy_shared_perform(args, arg_size, &info, &p->htop, &p->off_heap);
DESTROY_SHCOPY(info);
#else
p->arg_reg[2] = copy_struct(args, arg_size, &p->htop, &p->off_heap);
#endif
- BM_MESSAGE_COPIED(arg_size);
- BM_SWAP_TIMER(copy,system);
p->arity = 3;
p->fvalue = NIL;
@@ -12826,9 +12813,6 @@ erts_continue_exit_process(Process *p)
dep = (p->flags & F_DISTRIBUTION) ? erts_this_dist_entry : NULL;
erts_smp_proc_unlock(p, ERTS_PROC_LOCKS_ALL);
-#ifdef BM_COUNTERS
- processes_busy--;
-#endif
if (dep) {
erts_do_net_exits(dep, reason);
diff --git a/erts/emulator/beam/erl_process.h b/erts/emulator/beam/erl_process.h
index 7c98b60647..714e63e986 100644
--- a/erts/emulator/beam/erl_process.h
+++ b/erts/emulator/beam/erl_process.h
@@ -989,8 +989,7 @@ struct process {
Uint32 rcount; /* suspend count */
int schedule_count; /* Times left to reschedule a low prio process */
Uint reds; /* No of reductions for this process */
- Eterm group_leader; /* Pid in charge
- (can be boxed) */
+ Eterm group_leader; /* Pid in charge (can be boxed) */
Uint flags; /* Trap exit, etc (no trace flags anymore) */
Eterm fvalue; /* Exit & Throw value (failure reason) */
Uint freason; /* Reason for detected failure */
diff --git a/erts/emulator/beam/erl_trace.c b/erts/emulator/beam/erl_trace.c
index 4cf38bf894..d14d237ca6 100644
--- a/erts/emulator/beam/erl_trace.c
+++ b/erts/emulator/beam/erl_trace.c
@@ -493,8 +493,8 @@ erts_get_system_seq_tracer(void)
if (st != erts_tracer_nil &&
call_enabled_tracer(st, NULL, TRACE_FUN_ENABLED,
am_trace_status, am_undefined) == am_remove) {
- erts_set_system_seq_tracer(NULL, 0, erts_tracer_nil);
- st = erts_tracer_nil;
+ st = erts_set_system_seq_tracer(NULL, 0, erts_tracer_nil);
+ ERTS_TRACER_CLEAR(&st);
}
return st;
diff --git a/erts/emulator/beam/export.h b/erts/emulator/beam/export.h
index 8c81cbd410..1e7bb8514b 100644
--- a/erts/emulator/beam/export.h
+++ b/erts/emulator/beam/export.h
@@ -21,14 +21,8 @@
#ifndef __EXPORT_H__
#define __EXPORT_H__
-#ifndef __SYS_H__
#include "sys.h"
-#endif
-
-#ifndef __INDEX_H__
#include "index.h"
-#endif
-
#include "code_ix.h"
/*
diff --git a/erts/emulator/beam/global.h b/erts/emulator/beam/global.h
index f3d4ac56cd..8933bcad16 100644
--- a/erts/emulator/beam/global.h
+++ b/erts/emulator/beam/global.h
@@ -35,7 +35,6 @@
#include "register.h"
#include "erl_fun.h"
#include "erl_node_tables.h"
-#include "benchmark.h"
#include "erl_process.h"
#include "erl_sys_driver.h"
#include "erl_debug.h"
diff --git a/erts/emulator/beam/hash.h b/erts/emulator/beam/hash.h
index 9f773d8faa..4e769c0119 100644
--- a/erts/emulator/beam/hash.h
+++ b/erts/emulator/beam/hash.h
@@ -25,9 +25,7 @@
#ifndef __HASH_H__
#define __HASH_H__
-#ifndef __SYS_H__
#include "sys.h"
-#endif
typedef unsigned long HashValue;
typedef struct hash Hash;
diff --git a/erts/emulator/beam/index.h b/erts/emulator/beam/index.h
index 218779c33b..0a109d8699 100644
--- a/erts/emulator/beam/index.h
+++ b/erts/emulator/beam/index.h
@@ -26,13 +26,8 @@
#ifndef __INDEX_H__
#define __INDEX_H__
-#ifndef __HASH_H__
#include "hash.h"
-#endif
-
-#ifndef ERL_ALLOC_H__
#include "erl_alloc.h"
-#endif
typedef struct index_slot
{
diff --git a/erts/emulator/beam/module.h b/erts/emulator/beam/module.h
index 4e12731d85..5a60bc90d9 100644
--- a/erts/emulator/beam/module.h
+++ b/erts/emulator/beam/module.h
@@ -21,9 +21,7 @@
#ifndef __MODULE_H__
#define __MODULE_H__
-#ifndef __INDEX_H__
#include "index.h"
-#endif
struct erl_module_instance {
BeamCodeHeader* code_hdr;
diff --git a/erts/emulator/beam/safe_hash.h b/erts/emulator/beam/safe_hash.h
index 6910b33004..285103cb17 100644
--- a/erts/emulator/beam/safe_hash.h
+++ b/erts/emulator/beam/safe_hash.h
@@ -26,14 +26,9 @@
#ifndef __SAFE_HASH_H__
#define __SAFE_HASH_H__
-
-#ifndef __SYS_H__
#include "sys.h"
-#endif
-
#include "erl_alloc.h"
-
typedef unsigned long SafeHashValue;
typedef int (*SHCMP_FUN)(void*, void*);
diff --git a/erts/emulator/hipe/hipe_amd64_asm.m4 b/erts/emulator/hipe/hipe_amd64_asm.m4
index 2c0fbbee2d..409fd0ef89 100644
--- a/erts/emulator/hipe/hipe_amd64_asm.m4
+++ b/erts/emulator/hipe/hipe_amd64_asm.m4
@@ -121,6 +121,22 @@ define(NSP,%rsp)dnl
/*
+ * Debugging macros
+ *
+ * Keeps track of whether context has been saved in the debug build, allowing us
+ * to detect when the garbage collector is called when it shouldn't.
+ */
+`#ifdef DEBUG
+# define SET_GC_UNSAFE \
+ movq $1, P_GCUNSAFE(P)
+# define SET_GC_SAFE \
+ movq $0, P_GCUNSAFE(P)
+#else
+# define SET_GC_UNSAFE
+# define SET_GC_SAFE
+#endif'
+
+/*
* Context switching macros.
*/
`#define SWITCH_C_TO_ERLANG_QUICK \
@@ -133,12 +149,14 @@ define(NSP,%rsp)dnl
`#define SAVE_CACHED_STATE \
SAVE_HP; \
- SAVE_FCALLS'
+ SAVE_FCALLS; \
+ SET_GC_SAFE'
`#define RESTORE_CACHED_STATE \
RESTORE_HP; \
RESTORE_HEAP_LIMIT; \
- RESTORE_FCALLS'
+ RESTORE_FCALLS; \
+ SET_GC_UNSAFE'
`#define SWITCH_C_TO_ERLANG \
RESTORE_CACHED_STATE; \
diff --git a/erts/emulator/hipe/hipe_amd64_bifs.m4 b/erts/emulator/hipe/hipe_amd64_bifs.m4
index 9cf3bf74fd..21739726bb 100644
--- a/erts/emulator/hipe/hipe_amd64_bifs.m4
+++ b/erts/emulator/hipe/hipe_amd64_bifs.m4
@@ -600,10 +600,11 @@ noproc_primop_interface_0(nbif_handle_fp_exception, erts_restore_fpu)
define(gc_bif_interface_0,`nofail_primop_interface_0($1, $2)')
/*
- * Implement gc_bif_interface_N as standard_bif_interface_N (N=1,2).
+ * Implement gc_bif_interface_N as standard_bif_interface_N (N=1,2,3).
*/
define(gc_bif_interface_1,`standard_bif_interface_1($1, $2)')
define(gc_bif_interface_2,`standard_bif_interface_2($1, $2)')
+define(gc_bif_interface_3,`standard_bif_interface_3($1, $2)')
/*
* Implement gc_nofail_primop_interface_1 as nofail_primop_interface_1.
diff --git a/erts/emulator/hipe/hipe_amd64_glue.S b/erts/emulator/hipe/hipe_amd64_glue.S
index b37ed3c68a..f3404888d5 100644
--- a/erts/emulator/hipe/hipe_amd64_glue.S
+++ b/erts/emulator/hipe/hipe_amd64_glue.S
@@ -94,6 +94,7 @@ ASYM(nbif_return):
.nosave_exit:
/* switch to C stack */
SWITCH_ERLANG_TO_C_QUICK
+ SET_GC_SAFE
/* restore C callee-save registers, drop frame, return */
movq (%rsp), %rbp # kills P
movq 8(%rsp), %rbx
@@ -398,6 +399,7 @@ nbif_4_simple_exception:
movl %eax, P_NARITY(P) # Note: narity is a 32-bit field
/* find and prepare to invoke the handler */
SWITCH_ERLANG_TO_C_QUICK # The cached state is clean and need not be saved.
+ SET_GC_SAFE
movq P, %rdi
call CSYM(hipe_handle_exception) # Note: hipe_handle_exception() conses
SWITCH_C_TO_ERLANG # %rsp updated by hipe_find_handler()
diff --git a/erts/emulator/hipe/hipe_arm_asm.m4 b/erts/emulator/hipe/hipe_arm_asm.m4
index ae9ec752bb..68a6faa70b 100644
--- a/erts/emulator/hipe/hipe_arm_asm.m4
+++ b/erts/emulator/hipe/hipe_arm_asm.m4
@@ -48,6 +48,24 @@ define(NR_ARG_REGS,3)dnl admissible values are 0 to 6, inclusive
`#define TEMP_LR r8'
/*
+ * Debugging macros
+ *
+ * Keeps track of whether context has been saved in the debug build, allowing us
+ * to detect when the garbage collector is called when it shouldn't.
+ */
+`#ifdef DEBUG
+# define SET_GC_UNSAFE(SCRATCH) \
+ mov SCRATCH, #1; \
+ str SCRATCH, [P, #P_GCUNSAFE]
+# define SET_GC_SAFE(SCRATCH) \
+ mov SCRATCH, #0; \
+ str SCRATCH, [P, #P_GCUNSAFE]
+#else
+# define SET_GC_UNSAFE(SCRATCH)
+# define SET_GC_SAFE(SCRATCH)
+#endif'
+
+/*
* Context switching macros.
*
* RESTORE_CONTEXT and RESTORE_CONTEXT_QUICK do not affect
@@ -59,12 +77,14 @@ define(NR_ARG_REGS,3)dnl admissible values are 0 to 6, inclusive
`#define RESTORE_CONTEXT_QUICK \
mov lr, TEMP_LR'
-`#define SAVE_CACHED_STATE \
- str HP, [P, #P_HP]; \
- str NSP, [P, #P_NSP]'
+`#define SAVE_CACHED_STATE \
+ str HP, [P, #P_HP]; \
+ str NSP, [P, #P_NSP]; \
+ SET_GC_SAFE(HP)'
-`#define RESTORE_CACHED_STATE \
- ldr HP, [P, #P_HP]; \
+`#define RESTORE_CACHED_STATE \
+ SET_GC_UNSAFE(HP); \
+ ldr HP, [P, #P_HP]; \
ldr NSP, [P, #P_NSP]'
`#define SAVE_CONTEXT_BIF \
@@ -75,12 +95,14 @@ define(NR_ARG_REGS,3)dnl admissible values are 0 to 6, inclusive
ldr HP, [P, #P_HP]'
`#define SAVE_CONTEXT_GC \
+ SET_GC_SAFE(TEMP_LR); \
mov TEMP_LR, lr; \
str lr, [P, #P_NRA]; \
str NSP, [P, #P_NSP]; \
str HP, [P, #P_HP]'
`#define RESTORE_CONTEXT_GC \
+ SET_GC_UNSAFE(HP); \
ldr HP, [P, #P_HP]'
/*
diff --git a/erts/emulator/hipe/hipe_arm_bifs.m4 b/erts/emulator/hipe/hipe_arm_bifs.m4
index d9c9952dbf..d7a2fec04a 100644
--- a/erts/emulator/hipe/hipe_arm_bifs.m4
+++ b/erts/emulator/hipe/hipe_arm_bifs.m4
@@ -198,8 +198,9 @@ $1:
* gc_bif_interface_0(nbif_name, cbif_name)
* gc_bif_interface_1(nbif_name, cbif_name)
* gc_bif_interface_2(nbif_name, cbif_name)
+ * gc_bif_interface_3(nbif_name, cbif_name)
*
- * Generate native interface for a BIF with 0-2 parameters and
+ * Generate native interface for a BIF with 0-3 parameters and
* standard failure mode.
* The BIF may do a GC.
*/
@@ -279,6 +280,36 @@ $1:
.type $1, %function
#endif')
+define(gc_bif_interface_3,
+`
+#ifndef HAVE_$1
+#`define' HAVE_$1
+ .global $1
+$1:
+ /* Set up C argument registers. */
+ mov r0, P
+ NBIF_ARG(r1,3,0)
+ NBIF_ARG(r2,3,1)
+ NBIF_ARG(r3,3,2)
+
+ /* Save caller-save registers and call the C function. */
+ SAVE_CONTEXT_GC
+ str r1, [r0, #P_ARG0] /* Store BIF__ARGS in def_arg_reg[] */
+ str r2, [r0, #P_ARG1]
+ str r3, [r0, #P_ARG2]
+ add r1, r0, #P_ARG0
+ CALL_BIF($2)
+ TEST_GOT_MBUF(3)
+
+ /* Restore registers. Check for exception. */
+ cmp r0, #THE_NON_VALUE
+ RESTORE_CONTEXT_GC
+ beq nbif_3_simple_exception
+ NBIF_RET(3)
+ .size $1, .-$1
+ .type $1, %function
+#endif')
+
/*
* gc_nofail_primop_interface_1(nbif_name, cbif_name)
*
diff --git a/erts/emulator/hipe/hipe_arm_glue.S b/erts/emulator/hipe/hipe_arm_glue.S
index 49ffa8b1d8..5b7f8ad52d 100644
--- a/erts/emulator/hipe/hipe_arm_glue.S
+++ b/erts/emulator/hipe/hipe_arm_glue.S
@@ -342,6 +342,7 @@ nbif_4_gc_after_bif:
str r1, [P, #P_NARITY]
str TEMP_LR, [P, #P_NRA]
str NSP, [P, #P_NSP]
+ SET_GC_SAFE(TEMP_LR)
mov TEMP_LR, lr
mov r3, #0 /* Pass 0 in arity */
mov r2, #0 /* Pass NULL in regs */
@@ -349,6 +350,7 @@ nbif_4_gc_after_bif:
mov r0, P
bl erts_gc_after_bif_call
mov lr, TEMP_LR
+ SET_GC_UNSAFE(TEMP_LR)
ldr TEMP_LR, [P, #P_NRA]
mov r1, #0
str r1, [P, #P_NARITY]
@@ -404,6 +406,7 @@ nbif_4_simple_exception:
str NSP, [P, #P_NSP]
str TEMP_LR, [P, #P_NRA]
str r1, [P, #P_NARITY]
+ SET_GC_SAFE(r0)
/* find and prepare to invoke the handler */
mov r0, P
bl hipe_handle_exception /* Note: hipe_handle_exception() conses */
@@ -423,6 +426,7 @@ nbif_4_simple_exception:
str NSP, [P, #P_NSP]
str r1, [P, #P_NARITY]
str TEMP_LR, [P, #P_NRA]
+ SET_GC_SAFE(NSP)
b .nosave_exit
/*
diff --git a/erts/emulator/hipe/hipe_bif1.c b/erts/emulator/hipe/hipe_bif1.c
index 08adbd474e..5e127755c6 100644
--- a/erts/emulator/hipe/hipe_bif1.c
+++ b/erts/emulator/hipe/hipe_bif1.c
@@ -124,757 +124,3 @@ BIF_RETTYPE hipe_bifs_trap_count_clear_0(BIF_ALIST_0)
hipe_trap_count = 0;
BIF_RET(make_small(count));
}
-
-/*****************************************************************************
- * BIFs for benchmarking. These only do useful things if
- * __BENCHMARK__ is defined in beam/benchmark.h. For documentation
- * about how to add new counters or maintain the existing counters,
- * see benchmark.h.
- *
- * If benchmarking is not enabled all BIFs will return false. If the
- * required benchmark feature is not enabled, the counter will remain
- * zero.
- *
- * process_info/0 -> { Number of live processes,
- * Processes spawned in total }
- *
- * Live processes are increased when a new process is created, and
- * decreased when a process dies. Processes spawned is increased
- * when a process is created.
- *
- *
- * process_info_clear/0 -> true
- *
- * Will reset the processes spawned-counters to zero. If this is
- * done at some improper time, live processes may become a negative
- * value. This is not a problem in itself, just as long as you know
- * about it.
- *
- *
- * message_info/0 -> { Messages sent,
- * Messages copied,
- * Ego messages (sender = receiver),
- * Words sent,
- * Words copied,
- * Words preallocated }
- *
- * Counting the words sent in a shared heap system will affect
- * runtime performance since it means that we have to calculate the
- * size of the mesage. With private heaps, this is done anyway and
- * will not affect performance.
- *
- *
- * message_info_clear/0 -> true
- *
- * Reset the message counters to zero.
- *
- *
- * message_sizes/0 -> true
- *
- * Displays a text-mode bar diagram with message sizes. There are no
- * guaranties that this is printed in a way the Erlang system is
- * supposed to print things.
- *
- *
- * gc_info/0 -> { Minor collections,
- * Major collections,
- * Used heap,
- * Allocated heap,
- * Max used heap,
- * Max allocated heap }
- *
- * Information about private heap garbage collections. Number of
- * minor and major collections, how much heap is used and allocated
- * and how much heap has been in use and allocated at most since the
- * counters were reset.
- *
- *
- * shared_gc_info/0 -> { Minor collections of the shared heap,
- * Major collections of the shared heap,
- * Used shared heap,
- * Allocated shared heap,
- * Max used shared heap,
- * Max allocated shared heap }
- *
- * The same as above, but for the shared heap / message area. Note,
- * that in a shared heap system the max used heap and max allocated
- * heap are mostly the same, since the heap allways is filled before
- * a garbage collection, and most garbage collections do not enlarge
- * the heap. The private heap numbers are much more interesting.
- *
- *
- * incremental_gc_info/0 -> { Complete minor GC cycles,
- * Complete major GC cycles,
- * Minor GC stages,
- * Major GC stages }
- *
- *
- * gc_info_clear/0 -> true
- *
- * Reset counters for both private and shared garbage collection.
- *
- *
- * BM Timers
- * ---------
- *
- * All timers returns tuples of the kind: { Minutes, Seconds, Milliseconds }
- * except for the max times in garbage collection where times are normally
- * small. The tuple is therefor: { Seconds, Milliseconds, Microseconds }
- *
- * system_timer/0 -> Mutator time
- *
- * This timer is not a real-time clock, it only runs when a process
- * is scheduled to run. You can not find out the accual time a
- * program has taken to run using this timer.
- *
- *
- * system_timer_clear/0 -> true
- *
- * Reset system timer to zero.
- *
- *
- * send_timer/0 -> { Send time,
- * Copy time,
- * Size time }
- *
- * Time spent in sending messages. The copy time and size time are
- * only active if the copying is needed in send. Copying of data
- * into ETS-tables etc is not timed with this timer.
- *
- *
- * send_timer_clear/0 -> true
- *
- * Reset send timers to zero.
- *
- *
- * gc_timer/0 -> { Time in minor collection,
- * Time in major collection,
- * Max time in minor collection (�s),
- * Max time in major collection (�s) }
- *
- * Total time spent in garbage collection of the private heaps. The
- * max times are for one separate collection.
- *
- *
- * shared_gc_timer/0 -> { Time in minor collection,
- * Time in major collection,
- * Max time in minor collection (�s),
- * Max time in major collection (�s) }
- *
- * Total time spent in garbage collection of the shared heap /
- * message area. The max times are for one separate collection.
- *
- *
- * gc_timer_clear/0 -> true
- *
- * Reset private and shared garbage collection timers to zero. Note,
- * that the max-times are also reset.
- *
- *
- * misc_timer/0 -> { Misc 0, Misc 1, Misc 2 }
- *
- * Timers for debug purposes. In a normal system, these timers are
- * never used. Add these timers at places where you want to time
- * something not covered here. Use BM_SWAP_TIMER(from,to) to start
- * one of the misc timers.
- *
- * ... code timed by the system timer ...
- * BM_SWAP_TIMER(system,misc1);
- * ... code we want to time ...
- * BM_SWAP_TIMER(misc1,system);
- * ... back on system time ...
- *
- *
- * misc_timer_clear/0 -> true
- *
- * Reset misc timers to zero.
- */
-
-BIF_RETTYPE hipe_bifs_process_info_0(BIF_ALIST_0)
-{
-#ifdef __BENCHMARK__
-#ifndef BM_COUNTERS
- Uint processes_busy = 0;
- Uint processes_spawned = 0;
-#endif
- Eterm *hp;
-
- hp = HAlloc(BIF_P, 3);
- BIF_RET(TUPLE2(hp,
- make_small(processes_busy),
- make_small(processes_spawned)));
-#else
- BIF_RET(am_false);
-#endif
-}
-
-BIF_RETTYPE hipe_bifs_process_info_clear_0(BIF_ALIST_0)
-{
-#ifdef __BENCHMARK__
-#ifdef BM_COUNTERS
- processes_spawned = 0;
-#endif
- BIF_RET(am_true);
-#else
- BIF_RET(am_false);
-#endif
-}
-
-BIF_RETTYPE hipe_bifs_message_info_0(BIF_ALIST_0)
-{
-#ifdef __BENCHMARK__
- Eterm *hp;
-#ifndef BM_COUNTERS
- unsigned long messages_sent = 0;
- unsigned long messages_copied = 0;
- unsigned long messages_ego = 0;
-#endif
-#ifndef BM_MESSAGE_SIZES
- unsigned long words_sent = 0;
- unsigned long words_copied = 0;
- unsigned long words_prealloc = 0;
-#endif
-
- hp = HAlloc(BIF_P, 7);
- BIF_RET(TUPLE6(hp,
- make_small(messages_sent),
- make_small(messages_copied),
- make_small(messages_ego),
- make_small(words_sent),
- make_small(words_copied),
- make_small(words_prealloc)));
-#else
- BIF_RET(am_false);
-#endif
-}
-
-BIF_RETTYPE hipe_bifs_message_info_clear_0(BIF_ALIST_0)
-{
-#ifdef __BENCHMARK__
-#ifdef BM_COUNTERS
- messages_sent = 0;
- messages_copied = 0;
- messages_ego = 0;
-#endif
-#ifdef BM_MESSAGE_SIZES
- words_sent = 0;
- words_copied = 0;
- words_prealloc = 0;
- {
- int i;
- for (i = 0; i < 1000; i++)
- message_sizes[i] = 0;
- }
-#endif
- BIF_RET(am_true);
-#else
- BIF_RET(am_false);
-#endif
-}
-
-BIF_RETTYPE hipe_bifs_message_sizes_0(BIF_ALIST_0)
-{
-#ifdef BM_MESSAGE_SIZES
- int i, j, max = 0;
- int tmp[12] = {0,0,0,0,0,0,0,0,0,0,0,0};
-
- for (i = 0; i < 65; i++) {
- tmp[0] += message_sizes[i];
- if (tmp[0] > max)
- max = tmp[0];
- }
- for (i = 65; i < 999; i++) {
- tmp[i / 100 + 1] += message_sizes[i];
- if (tmp[i / 100 + 1] > max)
- max = tmp[i / 100 + 1];
- }
- tmp[11] = message_sizes[999];
- if (tmp[11] > max)
- max = tmp[11];
- for (i = -1; i < 11; i++) {
- int num = (tmp[i + 1] * 50) / max;
- if (i == -1)
- printf("\n\r 0 - 64: (%6d) |", tmp[0]);
- else if (i == 0)
- printf("\n\r 65 - 99: (%6d) |", tmp[1]);
- else if (i == 10)
- printf("\n\r >= 1000: (%6d) |", tmp[11]);
- else
- printf("\n\r%3d - %3d: (%6d) |", i * 100, i * 100 + 99,
- tmp[i + 1]);
-
- for (j = 0; j < num; j++)
- printf(".");
- }
- printf("\n\r");
-
- BIF_RET(am_true);
-#else
- BIF_RET(am_false);
-#endif
-}
-
-BIF_RETTYPE hipe_bifs_gc_info_0(BIF_ALIST_0)
-{
-#ifdef __BENCHMARK__
-#ifndef BM_COUNTERS
- Uint minor_gc = 0;
- Uint major_gc = 0;
-#endif
-#ifndef BM_HEAP_SIZES
- Uint max_used_heap = 0;
- Uint max_allocated_heap = 0;
-#endif
- Eterm *hp;
- Uint used_heap = (BIF_P->htop - BIF_P->heap) +
- (OLD_HTOP(BIF_P) - OLD_HEAP(BIF_P)) +
- MBUF_SIZE(BIF_P);
-
- Uint alloc_heap = (BIF_P->hend - BIF_P->heap) +
- (OLD_HEND(BIF_P) - OLD_HEAP(BIF_P)) +
- MBUF_SIZE(BIF_P);
-
- hp = HAlloc(BIF_P, 7);
- BIF_RET(TUPLE6(hp,
- make_small((Uint)minor_gc),
- make_small((Uint)major_gc),
- make_small((Uint)used_heap),
- make_small((Uint)alloc_heap),
- make_small(max_used_heap),
- make_small(max_allocated_heap)));
-#else
- BIF_RET(am_false);
-#endif
-}
-
-BIF_RETTYPE hipe_bifs_shared_gc_info_0(BIF_ALIST_0)
-{
-#ifdef __BENCHMARK__
-#if !(defined(BM_COUNTERS))
- Uint minor_global_gc = 0;
- Uint major_global_gc = 0;
-#endif
-#ifndef BM_HEAP_SIZES
- Uint max_used_global_heap = 0;
- Uint max_allocated_global_heap = 0;
-#endif
- Eterm *hp;
-
- Uint tmp_used_heap = 0;
- Uint tmp_allocated_heap = 0;
-
- hp = HAlloc(BIF_P, 7);
- BIF_RET(TUPLE6(hp,
- make_small((uint)minor_global_gc),
- make_small((uint)major_global_gc),
- make_small(tmp_used_heap),
- make_small(tmp_allocated_heap),
- make_small(max_used_global_heap),
- make_small(max_allocated_global_heap)));
-#else
- BIF_RET(am_false);
-#endif
-}
-
-BIF_RETTYPE hipe_bifs_incremental_gc_info_0(BIF_ALIST_0)
-{
-#ifdef __BENCHMARK__
-#if !defined(BM_COUNTERS)
- Uint minor_gc_cycles = 0;
- Uint major_gc_cycles = 0;
- Uint minor_gc_stages = 0;
- Uint major_gc_stages = 0;
-#endif
- Eterm *hp;
-
- hp = HAlloc(BIF_P, 5);
- BIF_RET(TUPLE4(hp,
- make_small(minor_gc_cycles),
- make_small(major_gc_cycles),
- make_small(minor_gc_stages),
- make_small(major_gc_stages)));
-#else
- BIF_RET(am_false);
-#endif
-}
-
-BIF_RETTYPE hipe_bifs_gc_info_clear_0(BIF_ALIST_0)
-{
-#ifdef __BENCHMARK__
-
-#ifdef BM_COUNTERS
- minor_gc = 0;
- major_gc = 0;
-#endif
-
-#ifdef BM_HEAP_SIZES
- max_used_heap = 0;
- max_allocated_heap = 0;
- max_used_global_heap = 0;
- max_allocated_global_heap = 0;
-#endif
-
- BIF_RET(am_true);
-#else
- BIF_RET(am_false);
-#endif
-}
-
-BIF_RETTYPE hipe_bifs_pause_times_0(BIF_ALIST_0)
-{
-#ifdef BM_TIMERS
- int i;
- int total_time = 0, n = 0;
- int left = 0, right = 0, mid = 0;
-
- printf("Pause times in minor collection:\r\n");
- for (i = 0; i < MAX_PAUSE_TIME; i++) {
- if (pause_times[i] > 0) {
- printf("%d: %ld\r\n", i, pause_times[i]);
- total_time += pause_times[i] * i;
- n += pause_times[i];
-
- if (i > mid)
- right += pause_times[i];
-
- while (right > left) {
- left += pause_times[mid++];
- right -= pause_times[mid];
- }
- }
- }
-
- printf("Number of collections: %d\r\n", n);
- printf("Total collection time: %d\r\n", total_time);
- if (n > 0)
- printf("Mean pause time: %d\r\n", total_time / n);
-
- printf("Geometrical mean: %d\r\n", mid);
-
- total_time = 0; n = 0;
- left = 0; right = 0; mid = 0;
- printf("Pause times in major collection:\r\n");
- for (i = 0; i < MAX_PAUSE_TIME; i++) {
- if (pause_times_old[i] > 0) {
- printf("%d: %ld\r\n", i, pause_times_old[i]);
- total_time += pause_times_old[i] * i;
- n += pause_times_old[i];
- }
- }
-
- printf("Number of collections: %d\r\n", n);
- printf("Total collection time: %d\r\n", total_time);
- if (n > 0)
- printf("Mean pause time: %d\r\n", total_time / n);
-
- BIF_RET(am_true);
-#else
- BIF_RET(am_false);
-#endif
-}
-
-/* XXX: these macros have free variables */
-#ifdef BM_TIMERS
-#define MAKE_TIME(_timer_) { \
- BM_TIMER_T tmp = _timer_##_time / 1000000; \
- milli = tmp % 1000; \
- tmp /= 1000; \
- sec = tmp % 60; \
- min = tmp / 60; }
-
-#define MAKE_MICRO_TIME(_timer_) { \
- BM_TIMER_T tmp = _timer_##_time / 1000; \
- micro = tmp % 1000; \
- tmp /= 1000; \
- milli = tmp % 1000; \
- sec = tmp / 1000; }
-
-#else
-#define MAKE_TIME(_timer_)
-#define MAKE_MICRO_TIME(_timer_)
-#endif
-
-BIF_RETTYPE hipe_bifs_system_timer_0(BIF_ALIST_0)
-{
-#ifdef __BENCHMARK__
- uint min = 0;
- uint sec = 0;
- uint milli = 0;
- Eterm *hp;
-
- hp = HAlloc(BIF_P, 4);
- MAKE_TIME(system);
- BIF_RET(TUPLE3(hp,
- make_small(min),
- make_small(sec),
- make_small(milli)));
-#else
- BIF_RET(am_false);
-#endif
-}
-
-BIF_RETTYPE hipe_bifs_system_timer_clear_0(BIF_ALIST_0)
-{
-#ifdef BM_TIMERS
- system_time = 0;
- BIF_RET(am_true);
-#else
- BIF_RET(am_false);
-#endif
-}
-
-BIF_RETTYPE hipe_bifs_send_timer_0(BIF_ALIST_0)
-{
-#ifdef __BENCHMARK__
- uint min = 0;
- uint sec = 0;
- uint milli = 0;
- Eterm *hp;
- Eterm sendtime, copytime, sizetime;
-
- hp = HAlloc(BIF_P, 4 * 4);
-
- MAKE_TIME(send);
- sendtime = TUPLE3(hp,
- make_small(min),
- make_small(sec),
- make_small(milli));
- hp += 4;
-
- MAKE_TIME(copy);
- copytime = TUPLE3(hp,
- make_small(min),
- make_small(sec),
- make_small(milli));
- hp += 4;
-
- MAKE_TIME(size);
- sizetime = TUPLE3(hp,
- make_small(min),
- make_small(sec),
- make_small(milli));
- hp += 4;
- BIF_RET(TUPLE3(hp, sendtime, copytime, sizetime));
-#else
- BIF_RET(am_false);
-#endif
-}
-
-BIF_RETTYPE hipe_bifs_send_timer_clear_0(BIF_ALIST_0)
-{
-#ifdef BM_TIMERS
- send_time = 0;
- copy_time = 0;
- size_time = 0;
- BIF_RET(am_true);
-#else
- BIF_RET(am_false);
-#endif
-}
-
-BIF_RETTYPE hipe_bifs_gc_timer_0(BIF_ALIST_0)
-{
-#ifdef __BENCHMARK__
- Eterm *hp;
- uint min = 0;
- uint sec = 0;
- uint milli = 0;
- uint micro = 0;
- Eterm minor, major, max_min, max_maj;
-
- hp = HAlloc(BIF_P, 4 * 4 + 5);
-
- MAKE_TIME(minor_gc);
- minor = TUPLE3(hp,
- make_small(min),
- make_small(sec),
- make_small(milli));
- hp += 4;
-
- MAKE_TIME(major_gc);
- major = TUPLE3(hp,
- make_small(min),
- make_small(sec),
- make_small(milli));
- hp += 4;
-
- MAKE_MICRO_TIME(max_minor);
- max_min = TUPLE3(hp,
- make_small(sec),
- make_small(milli),
- make_small(micro));
- hp += 4;
-
- MAKE_MICRO_TIME(max_major);
- max_maj = TUPLE3(hp,
- make_small(sec),
- make_small(milli),
- make_small(micro));
- hp += 4;
-
- BIF_RET(TUPLE4(hp, minor, major, max_min, max_maj));
-#else
- BIF_RET(am_false);
-#endif
-}
-
-BIF_RETTYPE hipe_bifs_shared_gc_timer_0(BIF_ALIST_0)
-{
-#ifdef __BENCHMARK__
- Eterm *hp;
- uint min = 0;
- uint sec = 0;
- uint milli = 0;
- uint micro = 0;
- Eterm minor, major, max_min, max_maj;
-
- hp = HAlloc(BIF_P, 4 * 4 + 5);
-
- MAKE_TIME(minor_global_gc);
- minor = TUPLE3(hp,
- make_small(min),
- make_small(sec),
- make_small(milli));
- hp += 4;
-
- MAKE_TIME(major_global_gc);
- major = TUPLE3(hp,
- make_small(min),
- make_small(sec),
- make_small(milli));
- hp += 4;
-
- MAKE_MICRO_TIME(max_global_minor);
- max_min = TUPLE3(hp,
- make_small(sec),
- make_small(milli),
- make_small(micro));
- hp += 4;
-
- MAKE_MICRO_TIME(max_global_major);
- max_maj = TUPLE3(hp,
- make_small(sec),
- make_small(milli),
- make_small(micro));
- hp += 4;
-
- BIF_RET(TUPLE4(hp, minor, major, max_min, max_maj));
-#else
- BIF_RET(am_false);
-#endif
-}
-
-BIF_RETTYPE hipe_bifs_gc_timer_clear_0(BIF_ALIST_0)
-{
-#ifdef BM_TIMERS
- minor_gc_time = 0;
- major_gc_time = 0;
- max_minor_time = 0;
- max_major_time = 0;
- minor_global_gc_time = 0;
- major_global_gc_time = 0;
- max_global_minor_time = 0;
- max_global_major_time = 0;
- BIF_RET(am_true);
-#else
- BIF_RET(am_false);
-#endif
-}
-
-BIF_RETTYPE hipe_bifs_misc_timer_0(BIF_ALIST_0)
-{
-#ifdef __BENCHMARK__
- uint min = 0;
- uint sec = 0;
- uint milli = 0;
- Eterm *hp;
- Eterm misctime1, misctime2, misctime3;
-
- hp = HAlloc(BIF_P, 4 * 4);
-
- MAKE_TIME(misc0);
- misctime1 = TUPLE3(hp,
- make_small(min),
- make_small(sec),
- make_small(milli));
- hp += 4;
-
- MAKE_TIME(misc1);
- misctime2 = TUPLE3(hp,
- make_small(min),
- make_small(sec),
- make_small(milli));
- hp += 4;
-
- MAKE_TIME(misc2);
- misctime3 = TUPLE3(hp,
- make_small(min),
- make_small(sec),
- make_small(milli));
- hp += 4;
- BIF_RET(TUPLE3(hp, misctime1, misctime2, misctime3));
-#else
- BIF_RET(am_false);
-#endif
-}
-
-BIF_RETTYPE hipe_bifs_misc_timer_clear_0(BIF_ALIST_0)
-{
-#ifdef BM_TIMERS
- misc0_time = 0;
- misc1_time = 0;
- misc2_time = 0;
- BIF_RET(am_true);
-#else
- BIF_RET(am_false);
-#endif
-}
-
-#undef MAKE_TIME
-#undef MAKE_MICRO_TIME
-
-/*
- * HiPE hrvtime().
- * These implementations are currently available:
- * + The fallback, which is the same as {X,_} = runtime(statistics).
- */
-
-static double fallback_get_hrvtime(void)
-{
- unsigned long ms_user;
-
- elapsed_time_both(&ms_user, NULL, NULL, NULL);
- return (double)ms_user;
-}
-
-/*
- * Fallback, if nothing better exists.
- * This is the same as {X,_} = statistics(runtime), which uses
- * times(2) on Unix systems.
- */
-
-#define hrvtime_is_started() 1
-#define start_hrvtime() do{}while(0)
-#define stop_hrvtime() do{}while(0)
-#define get_hrvtime() fallback_get_hrvtime()
-
-BIF_RETTYPE hipe_bifs_get_hrvtime_0(BIF_ALIST_0)
-{
- Eterm *hp;
- Eterm res;
- FloatDef f;
-
- if (!hrvtime_is_started())
- start_hrvtime();
- f.fd = get_hrvtime();
- hp = HAlloc(BIF_P, FLOAT_SIZE_OBJECT);
- res = make_float(hp);
- PUT_DOUBLE(f, hp);
- BIF_RET(res);
-}
-
-BIF_RETTYPE hipe_bifs_stop_hrvtime_0(BIF_ALIST_0)
-{
- stop_hrvtime();
- BIF_RET(am_true);
-}
diff --git a/erts/emulator/hipe/hipe_bif1.tab b/erts/emulator/hipe/hipe_bif1.tab
index c5b452f199..4be0ad0e9c 100644
--- a/erts/emulator/hipe/hipe_bif1.tab
+++ b/erts/emulator/hipe/hipe_bif1.tab
@@ -27,24 +27,3 @@ bif hipe_bifs:call_count_get/1
bif hipe_bifs:call_count_clear/1
bif hipe_bifs:trap_count_get/0
bif hipe_bifs:trap_count_clear/0
-bif hipe_bifs:process_info/0
-bif hipe_bifs:process_info_clear/0
-bif hipe_bifs:message_info/0
-bif hipe_bifs:message_info_clear/0
-bif hipe_bifs:message_sizes/0
-bif hipe_bifs:gc_info/0
-bif hipe_bifs:shared_gc_info/0
-bif hipe_bifs:incremental_gc_info/0
-bif hipe_bifs:gc_info_clear/0
-bif hipe_bifs:pause_times/0
-bif hipe_bifs:system_timer/0
-bif hipe_bifs:system_timer_clear/0
-bif hipe_bifs:send_timer/0
-bif hipe_bifs:send_timer_clear/0
-bif hipe_bifs:gc_timer/0
-bif hipe_bifs:shared_gc_timer/0
-bif hipe_bifs:gc_timer_clear/0
-bif hipe_bifs:misc_timer/0
-bif hipe_bifs:misc_timer_clear/0
-bif hipe_bifs:get_hrvtime/0
-bif hipe_bifs:stop_hrvtime/0
diff --git a/erts/emulator/hipe/hipe_bif_list.m4 b/erts/emulator/hipe/hipe_bif_list.m4
index 29095a5389..dcf3447af9 100644
--- a/erts/emulator/hipe/hipe_bif_list.m4
+++ b/erts/emulator/hipe/hipe_bif_list.m4
@@ -96,6 +96,7 @@
* gc_bif_interface_0(nbif_name, cbif_name)
* gc_bif_interface_1(nbif_name, cbif_name)
* gc_bif_interface_2(nbif_name, cbif_name)
+ * gc_bif_interface_3(nbif_name, cbif_name)
*
* A BIF which may do a GC or walk the native stack.
* May read NSP, NSP_LIMIT, NRA, HP, HP_LIMIT, and FCALLS.
@@ -263,32 +264,34 @@ noproc_primop_interface_1(nbif_atomic_inc, hipe_atomic_inc)
',)dnl
/*
- * Standard BIFs.
- * BIF_LIST(ModuleAtom,FunctionAtom,Arity,CFun,Index)
+ * BIFs that disable GC while trapping are called via a wrapper
+ * to reserve stack space for the "trap frame".
+ * They occasionally need to call the garbage collector in order to make room
+ * for the trap frame on the BEAM stack.
*/
+gc_bif_interface_1(nbif_term_to_binary_1, hipe_wrapper_term_to_binary_1)
+gc_bif_interface_2(nbif_term_to_binary_2, hipe_wrapper_term_to_binary_2)
+gc_bif_interface_1(nbif_binary_to_term_1, hipe_wrapper_binary_to_term_1)
+gc_bif_interface_2(nbif_binary_to_term_2, hipe_wrapper_binary_to_term_2)
+gc_bif_interface_1(nbif_binary_to_list_1, hipe_wrapper_binary_to_list_1)
+gc_bif_interface_3(nbif_binary_to_list_3, hipe_wrapper_binary_to_list_3)
+gc_bif_interface_1(nbif_bitstring_to_list_1, hipe_wrapper_bitstring_to_list_1)
+gc_bif_interface_1(nbif_list_to_binary_1, hipe_wrapper_list_to_binary_1)
+gc_bif_interface_1(nbif_iolist_to_binary_1, hipe_wrapper_iolist_to_binary_1)
+gc_bif_interface_1(nbif_binary_list_to_bin_1, hipe_wrapper_binary_list_to_bin_1)
+gc_bif_interface_1(nbif_list_to_bitstring_1, hipe_wrapper_list_to_bitstring_1)
+gc_bif_interface_2(nbif_send_2, hipe_wrapper_send_2)
+gc_bif_interface_3(nbif_send_3, hipe_wrapper_send_3)
+gc_bif_interface_2(nbif_ebif_bang_2, hipe_wrapper_ebif_bang_2)
+gc_bif_interface_2(nbif_maps_merge_2, hipe_wrapper_maps_merge_2)
-/* BIFs that disable GC while trapping are called via a wrapper
- * to reserve stack space for the "trap frame".
+
+/*
+ * Standard BIFs.
+ * BIF_LIST(ModuleAtom,FunctionAtom,Arity,CFun,Index)
*/
-define(CFUN,`ifelse(
-$1, term_to_binary_1, hipe_wrapper_$1,
-$1, term_to_binary_2, hipe_wrapper_$1,
-$1, binary_to_term_1, hipe_wrapper_$1,
-$1, binary_to_term_2, hipe_wrapper_$1,
-$1, binary_to_list_1, hipe_wrapper_$1,
-$1, binary_to_list_3, hipe_wrapper_$1,
-$1, bitstring_to_list_1, hipe_wrapper_$1,
-$1, list_to_binary_1, hipe_wrapper_$1,
-$1, iolist_to_binary_1, hipe_wrapper_$1,
-$1, binary_list_to_bin_1, hipe_wrapper_$1,
-$1, list_to_bitstring_1, hipe_wrapper_$1,
-$1, send_2, hipe_wrapper_$1,
-$1, send_3, hipe_wrapper_$1,
-$1, ebif_bang_2, hipe_wrapper_$1,
-$1, maps_merge_2, hipe_wrapper_$1,
-$1)')
-define(BIF_LIST,`standard_bif_interface_$3(nbif_$4, CFUN($4))')
+define(BIF_LIST,`standard_bif_interface_$3(nbif_$4, $4)')
include(TARGET/`erl_bif_list.h')
/*
diff --git a/erts/emulator/hipe/hipe_gc.c b/erts/emulator/hipe/hipe_gc.c
index d0619a0609..566c65882e 100644
--- a/erts/emulator/hipe/hipe_gc.c
+++ b/erts/emulator/hipe/hipe_gc.c
@@ -46,6 +46,8 @@ Eterm *fullsweep_nstack(Process *p, Eterm *n_htop)
/* arch-specific nstack walk state */
struct nstack_walk_state walk_state;
+ ASSERT(!p->hipe.gc_is_unsafe);
+
if (!p->hipe.nstack) {
ASSERT(!p->hipe.nsp && !p->hipe.nstend);
return n_htop;
@@ -136,6 +138,8 @@ void gensweep_nstack(Process *p, Eterm **ptr_old_htop, Eterm **ptr_n_htop)
char *mature;
Uint mature_size;
+ ASSERT(!p->hipe.gc_is_unsafe);
+
if (!p->hipe.nstack) {
ASSERT(!p->hipe.nsp && !p->hipe.nstend);
return;
diff --git a/erts/emulator/hipe/hipe_mkliterals.c b/erts/emulator/hipe/hipe_mkliterals.c
index 0d3493ec6c..b9d4226705 100644
--- a/erts/emulator/hipe/hipe_mkliterals.c
+++ b/erts/emulator/hipe/hipe_mkliterals.c
@@ -525,6 +525,12 @@ static const struct rts_param rts_params[] = {
{ 51, "P_CALLEE_EXP", 1, offsetof(struct process, hipe.u.callee_exp) },
{ 52, "THE_NON_VALUE", 1, (int)THE_NON_VALUE },
+
+ { 53, "P_GCUNSAFE",
+#ifdef DEBUG
+ 1, offsetof(struct process, hipe.gc_is_unsafe)
+#endif
+ },
};
#define NR_PARAMS ARRAY_SIZE(rts_params)
diff --git a/erts/emulator/hipe/hipe_ppc_bifs.m4 b/erts/emulator/hipe/hipe_ppc_bifs.m4
index 57b4208bee..b540562185 100644
--- a/erts/emulator/hipe/hipe_ppc_bifs.m4
+++ b/erts/emulator/hipe/hipe_ppc_bifs.m4
@@ -212,8 +212,9 @@ ASYM($1):
* gc_bif_interface_0(nbif_name, cbif_name)
* gc_bif_interface_1(nbif_name, cbif_name)
* gc_bif_interface_2(nbif_name, cbif_name)
+ * gc_bif_interface_3(nbif_name, cbif_name)
*
- * Generate native interface for a BIF with 0-2 parameters and
+ * Generate native interface for a BIF with 0-3 parameters and
* standard failure mode.
* The BIF may do a GC.
*/
@@ -300,6 +301,39 @@ ASYM($1):
TYPE_FUNCTION(ASYM($1))
#endif')
+define(gc_bif_interface_3,
+`
+#ifndef HAVE_$1
+#`define' HAVE_$1
+ GLOBAL(ASYM($1))
+ASYM($1):
+ /* Set up C argument registers. */
+ mr r3, P
+ NBIF_ARG(r4,3,0)
+ NBIF_ARG(r5,3,1)
+ NBIF_ARG(r6,3,2)
+
+ /* Save caller-save registers and call the C function. */
+ SAVE_CONTEXT_GC
+ STORE r4, P_ARG0(r3) /* Store BIF__ARGS in def_arg_reg[] */
+ STORE r5, P_ARG1(r3)
+ STORE r6, P_ARG2(r3)
+ addi r4, r3, P_ARG0
+ CALL_BIF($2)
+ TEST_GOT_MBUF
+
+ /* Restore registers. Check for exception. */
+ CMPI r3, THE_NON_VALUE
+ RESTORE_CONTEXT_GC
+ beq- 1f
+ NBIF_RET(3)
+1: /* workaround for bc:s small offset operand */
+ b CSYM(nbif_3_simple_exception)
+ HANDLE_GOT_MBUF(3)
+ SET_SIZE(ASYM($1))
+ TYPE_FUNCTION(ASYM($1))
+#endif')
+
/*
* gc_nofail_primop_interface_1(nbif_name, cbif_name)
*
diff --git a/erts/emulator/hipe/hipe_process.h b/erts/emulator/hipe/hipe_process.h
index 21c4239753..a8d5972280 100644
--- a/erts/emulator/hipe/hipe_process.h
+++ b/erts/emulator/hipe/hipe_process.h
@@ -52,6 +52,9 @@ struct hipe_process_state {
#if defined(ERTS_ENABLE_LOCK_CHECK) && defined(ERTS_SMP)
void (*bif_callee)(void); /* When calling BIF's via debug wrapper */
#endif
+#ifdef DEBUG
+ UWord gc_is_unsafe; /* Nonzero when GC-required state is on stack */
+#endif
};
extern void hipe_arch_print_pcb(struct hipe_process_state *p);
@@ -68,6 +71,9 @@ static __inline__ void hipe_init_process(struct hipe_process_state *p)
p->nra = NULL;
#endif
p->narity = 0;
+#ifdef DEBUG
+ p->gc_is_unsafe = 0;
+#endif
}
static __inline__ void hipe_delete_process(struct hipe_process_state *p)
diff --git a/erts/emulator/hipe/hipe_sparc_bifs.m4 b/erts/emulator/hipe/hipe_sparc_bifs.m4
index 2e886ec1d1..1389beaa61 100644
--- a/erts/emulator/hipe/hipe_sparc_bifs.m4
+++ b/erts/emulator/hipe/hipe_sparc_bifs.m4
@@ -210,8 +210,9 @@ $1:
* gc_bif_interface_0(nbif_name, cbif_name)
* gc_bif_interface_1(nbif_name, cbif_name)
* gc_bif_interface_2(nbif_name, cbif_name)
+ * gc_bif_interface_3(nbif_name, cbif_name)
*
- * Generate native interface for a BIF with 0-2 parameters and
+ * Generate native interface for a BIF with 0-3 parameters and
* standard failure mode.
* The BIF may do a GC.
*/
@@ -295,6 +296,37 @@ $1:
.type $1, #function
#endif')
+define(gc_bif_interface_3,
+`
+#ifndef HAVE_$1
+#`define' HAVE_$1
+ .global $1
+$1:
+ /* Set up C argument registers. */
+ mov P, %o0
+ NBIF_ARG(%o1,3,0)
+ NBIF_ARG(%o2,3,1)
+ NBIF_ARG(%o3,3,2)
+
+ /* Save caller-save registers and call the C function. */
+ SAVE_CONTEXT_GC
+ st %o1, [%o0+P_ARG0] ! Store BIF__ARGS in def_arg_reg
+ st %o2, [%o0+P_ARG1]
+ st %o3, [%o0+P_ARG2]
+ add %o0, P_ARG0, %o1
+ CALL_BIF($2)
+ nop
+ TEST_GOT_MBUF
+
+ /* Restore registers. Check for exception. */
+ TEST_GOT_EXN(3)
+ RESTORE_CONTEXT_GC
+ NBIF_RET(3)
+ HANDLE_GOT_MBUF(3)
+ .size $1, .-$1
+ .type $1, #function
+#endif')
+
/*
* gc_nofail_primop_interface_1(nbif_name, cbif_name)
*
diff --git a/erts/emulator/hipe/hipe_x86_bifs.m4 b/erts/emulator/hipe/hipe_x86_bifs.m4
index b8ac5046d5..c0c149733c 100644
--- a/erts/emulator/hipe/hipe_x86_bifs.m4
+++ b/erts/emulator/hipe/hipe_x86_bifs.m4
@@ -671,10 +671,11 @@ noproc_primop_interface_0(nbif_handle_fp_exception, erts_restore_fpu)
define(gc_bif_interface_0,`nofail_primop_interface_0($1, $2)')
/*
- * Implement gc_bif_interface_N as standard_bif_interface_N (N=1,2).
+ * Implement gc_bif_interface_N as standard_bif_interface_N (N=1,2,3).
*/
define(gc_bif_interface_1,`standard_bif_interface_1($1, $2)')
define(gc_bif_interface_2,`standard_bif_interface_2($1, $2)')
+define(gc_bif_interface_3,`standard_bif_interface_3($1, $2)')
/*
* Implement gc_nofail_primop_interface_1 as nofail_primop_interface_1.
diff --git a/erts/emulator/sys/unix/erl_child_setup.c b/erts/emulator/sys/unix/erl_child_setup.c
index 6beb316350..6b9ddd8da4 100644
--- a/erts/emulator/sys/unix/erl_child_setup.c
+++ b/erts/emulator/sys/unix/erl_child_setup.c
@@ -54,6 +54,7 @@
#include <stdlib.h>
#include <stdio.h>
+#include <stdarg.h>
#include <sys/wait.h>
#define WANT_NONBLOCKING
@@ -74,15 +75,22 @@
//#define HARD_DEBUG
#ifdef HARD_DEBUG
-#define DEBUG_PRINT(fmt, ...) fprintf(stderr, fmt "\r\n", ##__VA_ARGS__)
+#define DEBUG_PRINT(fmt, ...) fprintf(stderr, "%d:" fmt "\r\n", getpid(), ##__VA_ARGS__)
#else
#define DEBUG_PRINT(fmt, ...)
#endif
-#define ABORT(fmt, ...) do { \
- fprintf(stderr, "erl_child_setup: " fmt "\r\n", ##__VA_ARGS__); \
- abort(); \
- } while(0)
+static char abort_reason[200]; /* for core dump inspection */
+
+static void ABORT(const char* fmt, ...)
+{
+ va_list arglist;
+ va_start(arglist, fmt);
+ vsprintf(abort_reason, fmt, arglist);
+ fprintf(stderr, "erl_child_setup: %s\r\n", abort_reason);
+ va_end(arglist);
+ abort();
+}
#ifdef DEBUG
void
@@ -123,12 +131,13 @@ static int sigchld_pipe[2];
static int
start_new_child(int pipes[])
{
+ int errln = -1;
int size, res, i, pos = 0;
char *buff, *o_buff;
- char *cmd, *wd, **new_environ, **args = NULL;
+ char *cmd, *cwd, *wd, **new_environ, **args = NULL;
- Sint cnt, flags;
+ Sint32 cnt, flags;
/* only child executes here */
@@ -137,6 +146,7 @@ start_new_child(int pipes[])
} while(res < 0 && (errno == EINTR || errno == ERRNO_BLOCK));
if (res <= 0) {
+ errln = __LINE__;
goto child_error;
}
@@ -148,10 +158,12 @@ start_new_child(int pipes[])
if ((res = read(pipes[0], buff + pos, size - pos)) < 0) {
if (errno == ERRNO_BLOCK || errno == EINTR)
continue;
+ errln = __LINE__;
goto child_error;
}
if (res == 0) {
errno = EPIPE;
+ errln = __LINE__;
goto child_error;
}
pos += res;
@@ -160,12 +172,16 @@ start_new_child(int pipes[])
o_buff = buff;
flags = get_int32(buff);
- buff += sizeof(Sint32);
+ buff += sizeof(flags);
DEBUG_PRINT("flags = %d", flags);
cmd = buff;
buff += strlen(buff) + 1;
+
+ cwd = buff;
+ buff += strlen(buff) + 1;
+
if (*buff == '\0') {
wd = NULL;
} else {
@@ -177,10 +193,10 @@ start_new_child(int pipes[])
DEBUG_PRINT("wd = %s", wd);
cnt = get_int32(buff);
- buff += sizeof(Sint32);
+ buff += sizeof(cnt);
new_environ = malloc(sizeof(char*)*(cnt + 1));
- DEBUG_PRINT("env_len = %ld", cnt);
+ DEBUG_PRINT("env_len = %d", cnt);
for (i = 0; i < cnt; i++, buff++) {
new_environ[i] = buff;
while(*buff != '\0') buff++;
@@ -190,7 +206,7 @@ start_new_child(int pipes[])
if (o_buff + size != buff) {
/* This is a spawn executable call */
cnt = get_int32(buff);
- buff += sizeof(Sint32);
+ buff += sizeof(cnt);
args = malloc(sizeof(char*)*(cnt + 1));
for (i = 0; i < cnt; i++, buff++) {
args[i] = buff;
@@ -201,7 +217,12 @@ start_new_child(int pipes[])
if (o_buff + size != buff) {
errno = EINVAL;
- goto child_error;
+ errln = __LINE__;
+ fprintf(stderr,"erl_child_setup: failed with protocol "
+ "error %d on line %d", errno, errln);
+ /* we abort here as it is most likely a symptom of an
+ emulator/erl_child_setup bug */
+ abort();
}
DEBUG_PRINT("read ack");
@@ -213,12 +234,32 @@ start_new_child(int pipes[])
ASSERT(res == sizeof(proto));
}
} while(res < 0 && (errno == EINTR || errno == ERRNO_BLOCK));
+
if (res < 1) {
errno = EPIPE;
+ errln = __LINE__;
goto child_error;
}
- DEBUG_PRINT("Do that forking business: '%s'\n",cmd);
+ DEBUG_PRINT("Set cwd to: '%s'",cwd);
+
+ if (chdir(cwd) < 0) {
+ /* This is not good, it probably means that the cwd of
+ beam is invalid. We ignore it and try anyways as
+ the child might now need a cwd or the chdir below
+ could take us to a valid directory.
+ */
+ }
+
+ DEBUG_PRINT("Set wd to: '%s'",wd);
+
+ if (wd && chdir(wd) < 0) {
+ int err = errno;
+ fprintf(stderr,"spawn: Could not cd to %s\r\n", wd);
+ _exit(err);
+ }
+
+ DEBUG_PRINT("Do that forking business: '%s'",cmd);
/* When the dup2'ing below is done, only
fd's 0, 1, 2 and maybe 3, 4 should survive the
@@ -228,25 +269,34 @@ start_new_child(int pipes[])
if (flags & FORKER_FLAG_USE_STDIO) {
/* stdin for process */
if (flags & FORKER_FLAG_DO_WRITE &&
- dup2(pipes[0], 0) < 0)
+ dup2(pipes[0], 0) < 0) {
+ errln = __LINE__;
goto child_error;
+ }
/* stdout for process */
if (flags & FORKER_FLAG_DO_READ &&
- dup2(pipes[1], 1) < 0)
+ dup2(pipes[1], 1) < 0) {
+ errln = __LINE__;
goto child_error;
+ }
}
else { /* XXX will fail if pipes[0] == 4 (unlikely..) */
- if (flags & FORKER_FLAG_DO_READ && dup2(pipes[1], 4) < 0)
+ if (flags & FORKER_FLAG_DO_READ && dup2(pipes[1], 4) < 0) {
+ errln = __LINE__;
goto child_error;
- if (flags & FORKER_FLAG_DO_WRITE && dup2(pipes[0], 3) < 0)
+ }
+ if (flags & FORKER_FLAG_DO_WRITE && dup2(pipes[0], 3) < 0) {
+ errln = __LINE__;
goto child_error;
+ }
}
- if (dup2(pipes[2], 2) < 0)
- goto child_error;
-
- if (wd && chdir(wd) < 0)
+ /* we do the dup2 of stderr last so that errors
+ in child_error will be printed to stderr */
+ if (dup2(pipes[2], 2) < 0) {
+ errln = __LINE__;
goto child_error;
+ }
#if defined(USE_SETPGRP_NOARGS) /* SysV */
(void) setpgrp();
@@ -268,9 +318,14 @@ start_new_child(int pipes[])
} else {
execle(SHELL, "sh", "-c", cmd, (char *) NULL, new_environ);
}
+
+ DEBUG_PRINT("exec error: %d",errno);
+ _exit(errno);
+
child_error:
- DEBUG_PRINT("exec error: %d\r\n",errno);
- _exit(128 + errno);
+ fprintf(stderr,"erl_child_setup: failed with error %d on line %d\r\n",
+ errno, errln);
+ _exit(errno);
}
@@ -461,7 +516,7 @@ main(int argc, char *argv[])
proto.action = ErtsSysForkerProtoAction_SigChld;
proto.u.sigchld.error_number = ibuff[1];
- DEBUG_PRINT("send %s to %d", buff, uds_fd);
+ DEBUG_PRINT("send sigchld to %d (errno = %d)", uds_fd, ibuff[1]);
if (write(uds_fd, &proto, sizeof(proto)) < 0) {
if (errno == EINTR)
continue;
diff --git a/erts/emulator/sys/unix/erl_unix_sys.h b/erts/emulator/sys/unix/erl_unix_sys.h
index 3a0d23cd36..b64b0d87f6 100644
--- a/erts/emulator/sys/unix/erl_unix_sys.h
+++ b/erts/emulator/sys/unix/erl_unix_sys.h
@@ -282,7 +282,7 @@ ERTS_GLB_INLINE ErtsSysPerfCounter erts_sys_perf_counter(void);
#if ERTS_GLB_INLINE_INCL_FUNC_DEF
-ERTS_GLB_INLINE ErtsSysPerfCounter
+ERTS_GLB_FORCE_INLINE ErtsSysPerfCounter
erts_sys_perf_counter()
{
return (*erts_sys_time_data__.r.o.perf_counter)();
diff --git a/erts/emulator/sys/unix/sys_drivers.c b/erts/emulator/sys/unix/sys_drivers.c
index 812112fb91..400f163652 100644
--- a/erts/emulator/sys/unix/sys_drivers.c
+++ b/erts/emulator/sys/unix/sys_drivers.c
@@ -554,7 +554,7 @@ static ErlDrvData spawn_start(ErlDrvPort port_num, char* name,
ErtsSysDriverData *dd;
char *cmd_line;
char wd_buff[MAXPATHLEN+1];
- char *wd;
+ char *wd, *cwd;
int ifd[2], ofd[2], stderrfd;
if (pipe(ifd) < 0) return ERL_DRV_ERROR_ERRNO;
@@ -631,24 +631,22 @@ static ErlDrvData spawn_start(ErlDrvPort port_num, char* name,
return ERL_DRV_ERROR_ERRNO;
}
- if (opts->wd == NULL) {
- if ((wd = getcwd(wd_buff, MAXPATHLEN+1)) == NULL) {
- /* on some OSs this call opens a fd in the
- background which means that this can
- return EMFILE */
- int err = errno;
- close_pipes(ifd, ofd);
- erts_free(ERTS_ALC_T_TMP, (void *) cmd_line);
- if (new_environ != environ)
- erts_free(ERTS_ALC_T_ENVIRONMENT, (void *) new_environ);
- erts_smp_rwmtx_runlock(&environ_rwmtx);
- errno = err;
- return ERL_DRV_ERROR_ERRNO;
- }
- } else {
- wd = opts->wd;
+ if ((cwd = getcwd(wd_buff, MAXPATHLEN+1)) == NULL) {
+ /* on some OSs this call opens a fd in the
+ background which means that this can
+ return EMFILE */
+ int err = errno;
+ close_pipes(ifd, ofd);
+ erts_free(ERTS_ALC_T_TMP, (void *) cmd_line);
+ if (new_environ != environ)
+ erts_free(ERTS_ALC_T_ENVIRONMENT, (void *) new_environ);
+ erts_smp_rwmtx_runlock(&environ_rwmtx);
+ errno = err;
+ return ERL_DRV_ERROR_ERRNO;
}
+ wd = opts->wd;
+
{
struct iovec *io_vector;
int iov_len = 5;
@@ -660,6 +658,8 @@ static ErlDrvData spawn_start(ErlDrvPort port_num, char* name,
| (opts->read_write & DO_READ ? FORKER_FLAG_DO_READ : 0)
| (opts->read_write & DO_WRITE ? FORKER_FLAG_DO_WRITE : 0);
+ if (wd) iov_len++;
+
/* count number of elements in environment */
while(new_environ[env_len] != NULL)
env_len++;
@@ -688,6 +688,10 @@ static ErlDrvData spawn_start(ErlDrvPort port_num, char* name,
return ERL_DRV_ERROR_ERRNO;
}
+ /*
+ * Whitebox test port_SUITE:pipe_limit_env
+ * assumes this command payload format.
+ */
io_vector[i].iov_base = (void*)&buffsz;
io_vector[i++].iov_len = sizeof(buffsz);
@@ -700,10 +704,16 @@ static ErlDrvData spawn_start(ErlDrvPort port_num, char* name,
io_vector[i++].iov_len = len;
buffsz += len;
- io_vector[i].iov_base = wd;
+ io_vector[i].iov_base = cwd;
io_vector[i].iov_len = strlen(io_vector[i].iov_base) + 1;
buffsz += io_vector[i++].iov_len;
+ if (wd) {
+ io_vector[i].iov_base = wd;
+ io_vector[i].iov_len = strlen(io_vector[i].iov_base) + 1;
+ buffsz += io_vector[i++].iov_len;
+ }
+
io_vector[i].iov_base = nullbuff;
io_vector[i++].iov_len = 1;
buffsz += io_vector[i-1].iov_len;
@@ -765,9 +775,14 @@ static ErlDrvData spawn_start(ErlDrvPort port_num, char* name,
if (res < (buffsz + sizeof(buffsz))) {
/* we only wrote part of the command payload. Enqueue the rest. */
for (i = 0; i < iov_len; i++) {
- driver_enq(port_num, io_vector[i].iov_base, io_vector[i].iov_len);
+ if (res >= io_vector[i].iov_len)
+ res -= io_vector[i].iov_len;
+ else {
+ driver_enq(port_num, io_vector[i].iov_base + res,
+ io_vector[i].iov_len - res);
+ res = 0;
+ }
}
- driver_deq(port_num, res);
driver_select(port_num, ofd[1], ERL_DRV_WRITE|ERL_DRV_USE, 1);
}
diff --git a/erts/emulator/test/port_SUITE.erl b/erts/emulator/test/port_SUITE.erl
index ee07699884..5c0bfdffd4 100644
--- a/erts/emulator/test/port_SUITE.erl
+++ b/erts/emulator/test/port_SUITE.erl
@@ -83,6 +83,7 @@
bad_port_messages/1,
basic_ping/1,
cd/1,
+ cd_relative/1,
close_deaf_port/1,
count_fds/1,
dying_port/1,
@@ -91,6 +92,7 @@
exit_status/1,
exit_status_multi_scheduling_block/1,
huge_env/1,
+ pipe_limit_env/1,
input_only/1,
iter_max_ports/1,
line/1,
@@ -137,7 +139,7 @@
win_massive_client/1
]).
--export([do_iter_max_ports/2]).
+-export([do_iter_max_ports/2, relative_cd/0]).
%% Internal exports.
-export([tps/3]).
@@ -158,7 +160,7 @@ all() ->
{group, multiple_packets}, parallell, dying_port,
port_program_with_path, open_input_file_port,
open_output_file_port, name1, env, huge_env, bad_env, cd,
- bad_args,
+ cd_relative, pipe_limit_env, bad_args,
exit_status, iter_max_ports, count_fds, t_exit, {group, tps}, line,
stderr_to_stdout, otp_3906, otp_4389, win_massive,
mix_up_ports, otp_5112, otp_5119,
@@ -1002,6 +1004,55 @@ huge_env(Config) when is_list(Config) ->
ct:fail("Open port failed ~p:~p",[E,R])
end.
+%% Test to spawn program with command payload buffer
+%% just around pipe capacity (9f779819f6bda734c5953468f7798)
+pipe_limit_env(Config) when is_list(Config) ->
+ Cmd = "true",
+ CmdSize = command_payload_size(Cmd),
+ Limits = [4096, 16384, 65536], % Try a couple of common pipe buffer sizes
+
+ lists:foreach(fun(Lim) ->
+ lists:foreach(fun(L) -> pipe_limit_env_do(L, Cmd, CmdSize)
+ end, lists:seq(Lim-5, Lim+5))
+ end, Limits),
+ ok.
+
+pipe_limit_env_do(Bytes, Cmd, CmdSize) ->
+ case env_of_bytes(Bytes-CmdSize) of
+ [] -> skip;
+ Env ->
+ try erlang:open_port({spawn,Cmd},[exit_status, {env, Env}]) of
+ P ->
+ receive
+ {P, {exit_status,N}} = M ->
+ %% Bug caused exit_status 150 (EINVAL+128)
+ 0 = N
+ end
+ catch E:R ->
+ %% Have to catch the error here, as printing the stackdump
+ %% in the ct log is way to heavy for some test machines.
+ ct:fail("Open port failed ~p:~p",[E,R])
+ end
+ end.
+
+%% environ format: KEY=VALUE\0
+env_of_bytes(Bytes) when Bytes > 3 ->
+ Env = [{"X",lists:duplicate(Bytes-3, $x)}];
+env_of_bytes(_) -> [].
+
+%% White box assumption about payload written to pipe
+%% for Cmd and current environment (see spawn_start in sys_driver.c)
+command_payload_size(Cmd) ->
+ EnvSize = lists:foldl(fun(E,Acc) -> length(E) + 1 + Acc end,
+ 0, os:getenv()),
+ {ok, PWD} = file:get_cwd(),
+ (4 % buffsz
+ + 4 % flags
+ + 5 + length(Cmd) + 1 % "exec $Cmd"
+ + length(PWD) + 1 % $PWD
+ + 1 % nullbuff
+ + 4 % env_len
+ + EnvSize).
%% Test bad 'args' options.
bad_args(Config) when is_list(Config) ->
@@ -1036,8 +1087,7 @@ cd(Config) when is_list(Config) ->
Cmd = Program ++ " -pz " ++ DataDir ++
" -noshell -s port_test pwd -s erlang halt",
_ = open_port({spawn, Cmd},
- [{cd, TestDir},
- {line, 256}]),
+ [{cd, TestDir}, {line, 256}]),
receive
{_, {data, {eol, String}}} ->
case filename_equal(String, TestDir) of
@@ -1063,7 +1113,74 @@ cd(Config) when is_list(Config) ->
Other3 ->
ct:fail({env, Other3})
end,
- ok.
+
+ InvalidDir = filename:join(DataDir, "invaliddir"),
+ try open_port({spawn, Cmd},
+ [{cd, InvalidDir}, exit_status, {line, 256}]) of
+ _ ->
+ receive
+ {_, {exit_status, _}} ->
+ ok;
+ Other4 ->
+ ct:fail({env, Other4})
+ end
+ catch error:eacces ->
+ %% This happens on Windows
+ ok
+ end,
+
+ %% Check that there are no lingering messages
+ receive
+ Other5 ->
+ ct:fail({env, Other5})
+ after 10 ->
+ ok
+ end.
+
+%% Test that an emulator that has set it's cwd to
+%% something other then when it started, can use
+%% relative {cd,"./"} to open port and that cd will
+%% be relative the new cwd and not the original
+cd_relative(Config) ->
+
+ Program = atom_to_list(lib:progname()),
+ DataDir = proplists:get_value(data_dir, Config),
+ TestDir = filename:join(DataDir, "dir"),
+
+ Cmd = Program ++ " -pz " ++ filename:dirname(code:where_is_file("port_SUITE.beam")) ++
+ " -noshell -s port_SUITE relative_cd -s erlang halt",
+
+ _ = open_port({spawn, Cmd}, [{line, 256}, {cd, TestDir}]),
+
+ receive
+ {_, {data, {eol, String}}} ->
+ case filename_equal(String, TestDir) of
+ true ->
+ ok;
+ false ->
+ ct:fail({cd_relative, String})
+ end;
+ Other ->
+ ct:fail(Other)
+ end.
+
+relative_cd() ->
+
+ Program = atom_to_list(lib:progname()),
+ ok = file:set_cwd(".."),
+ {ok, Cwd} = file:get_cwd(),
+
+ Cmd = Program ++ " -pz " ++ Cwd ++
+ " -noshell -s port_test pwd -s erlang halt",
+
+ _ = open_port({spawn, Cmd}, [{line, 256}, {cd, "./dir"}, exit_status]),
+
+ receive
+ {_, {data, {eol, String}}} ->
+ io:format("~s~n",[String]);
+ Other ->
+ io:format("ERROR: ~p~n",[Other])
+ end.
filename_equal(A, B) ->
case os:type() of
diff --git a/erts/emulator/test/trace_local_SUITE.erl b/erts/emulator/test/trace_local_SUITE.erl
index 74c05f24e0..c297acd78b 100644
--- a/erts/emulator/test/trace_local_SUITE.erl
+++ b/erts/emulator/test/trace_local_SUITE.erl
@@ -439,6 +439,14 @@ return_test() ->
?RT(?MODULE,slave,2),
shutdown(),
?NM,
+
+ %% Test a regression where turning off return_to tracing
+ %% on yourself would cause a segfault.
+ Pid = setup([call,return_to]),
+ erlang:trace_pattern({'_','_','_'},[],[local]),
+ apply_slave(erlang,trace,[Pid, false, [all]]),
+ shutdown(),
+
ok.
on_and_off_test() ->