⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 erl_mtrace.c

📁 OTP是开放电信平台的简称
💻 C
📖 第 1 页 / 共 2 页
字号:
/* ``The contents of this file are subject to the Erlang Public License, * Version 1.1, (the "License"); you may not use this file except in * compliance with the License. You should have received a copy of the * Erlang Public License along with this software. If not, it can be * retrieved via the world wide web at http://www.erlang.org/. *  * Software distributed under the License is distributed on an "AS IS" * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See * the License for the specific language governing rights and limitations * under the License. *  * The Initial Developer of the Original Code is Ericsson Utvecklings AB. * Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings * AB. All Rights Reserved.'' *  *     $Id$ *//* * Description:	Memory allocation trace. The trace is sent over a *              tcp/ip connection. * *              The trace format is not intended to be documented. *              Instead a library for parsing the trace will be *              distributed. This in order to more easily be able *              to make changes in the trace format. The library *              for parsing the trace is currently not included in *              the OTP distribution, but will be in the future. * * Author: 	Rickard Green */#ifdef HAVE_CONFIG_H#  include "config.h"#endif#include "sys.h"#include "global.h"#include "erl_sock.h"#include "erl_threads.h"#include "erl_memory_trace_protocol.h"#include "erl_mtrace.h"#if defined(MAXHOSTNAMELEN) && MAXHOSTNAMELEN > 255#  undef MAXHOSTNAMELEN#endif#ifndef MAXHOSTNAMELEN#  define MAXHOSTNAMELEN 255#endif#define TRACE_PRINTOUTS 0#ifdef TRACE_PRINTOUTS#define MSB2BITS(X) ((((unsigned)(X))+1)*8)#endifstatic erts_mtx_t mtrace_op_mutex;static erts_mtx_t mtrace_buf_mutex;#define TRACE_BUF_SZ 				(16*1024)#define UI8_MSB_EHF_SZ				ERTS_MT_UI8_MSB_EHDR_FLD_SZ#define UI16_MSB_EHF_SZ				ERTS_MT_UI16_MSB_EHDR_FLD_SZ#define UI32_MSB_EHF_SZ				ERTS_MT_UI32_MSB_EHDR_FLD_SZ#define UI64_MSB_EHF_SZ				ERTS_MT_UI64_MSB_EHDR_FLD_SZ#define UI_MSB_EHF_SZ				ERTS_MT_UI64_MSB_EHDR_FLD_SZ#define TAG_EHF_SZ				ERTS_MT_TAG_EHDR_FLD_SZ#define UI8_MSB_EHF_MSK				ERTS_MT_UI8_MSB_EHDR_FLD_MSK#define UI16_MSB_EHF_MSK			ERTS_MT_UI16_MSB_EHDR_FLD_MSK#define UI32_MSB_EHF_MSK			ERTS_MT_UI32_MSB_EHDR_FLD_MSK#define UI_MSB_EHF_MSK				ERTS_MT_UI64_MSB_EHDR_FLD_MSK#define UI64_MSB_EHF_MSK			ERTS_MT_UI64_MSB_EHDR_FLD_MSK#define TAG_EHF_MSK				ERTS_MT_TAG_EHDR_FLD_MSK#define UI8_SZ					(1)#define UI16_SZ					(2)#define UI32_SZ					(4)#define UI64_SZ					(8)#ifdef ARCH_64#  define UI_SZ					UI64_SZ#else#  define UI_SZ					UI32_SZ#endif#define WRITE_UI8(P, V) (*(P) = (byte) ((V) & 0xff))#define WRITE_UI16(P, V)						\  ((P)[0] = (byte) (((V) >>  8) & 0xff),				\   (P)[1] = (byte) ( (V)        & 0xff))#define WRITE_UI32(P, V)						\  ((P)[0] = (byte) (((V) >> 24) & 0xff),				\   (P)[1] = (byte) (((V) >> 16) & 0xff),				\   (P)[2] = (byte) (((V) >>  8) & 0xff),				\   (P)[3] = (byte) ( (V)        & 0xff))#define WRITE_UI64(P, V)						\  ((P)[0] = (byte) (((V) >> 56) & 0xff),				\   (P)[1] = (byte) (((V) >> 48) & 0xff),				\   (P)[2] = (byte) (((V) >> 40) & 0xff),				\   (P)[3] = (byte) (((V) >> 32) & 0xff),				\   (P)[4] = (byte) (((V) >> 24) & 0xff),				\   (P)[5] = (byte) (((V) >> 16) & 0xff),				\   (P)[6] = (byte) (((V) >>  8) & 0xff),				\   (P)[7] = (byte) ( (V)        & 0xff))#define PUT_UI8(P, V)  (WRITE_UI8((P),  (V)), (P) += UI8_SZ)#define PUT_UI16(P, V) (WRITE_UI16((P), (V)), (P) += UI16_SZ)#define PUT_UI32(P, V) (WRITE_UI32((P), (V)), (P) += UI32_SZ)#define PUT_UI64(P, V) (WRITE_UI64((P), (V)), (P) += UI64_SZ)#define PUT_VSZ_UI16(P, M, V)						\do {									\    Uint16 v__ = (Uint16) (V);						\    if (v__ >= (((Uint16) 1) << 8)) (M) = 1; else (M) = 0;		\    switch ((M)) {							\    case 1: *((P)++) = (byte) ((v__ >>  8) & 0xff);			\    case 0: *((P)++) = (byte) ( v__        & 0xff);			\    }									\} while (0)#define PUT_VSZ_UI32(P, M, V)						\do {									\    Uint32 v__ = (Uint32) (V);						\    if (v__ >= (((Uint32) 1) << 16)) {					\	if (v__ >= (((Uint32) 1) << 24)) (M) = 3; else (M) = 2;		\    } else {								\	if (v__ >= (((Uint32) 1) << 8)) (M) = 1; else (M) = 0;		\    }									\    switch ((M)) {							\    case 3: *((P)++) = (byte) ((v__ >> 24) & 0xff);			\    case 2: *((P)++) = (byte) ((v__ >> 16) & 0xff);			\    case 1: *((P)++) = (byte) ((v__ >>  8) & 0xff);			\    case 0: *((P)++) = (byte) ( v__        & 0xff);			\    }									\} while (0)#ifdef ARCH_64#define PUT_VSZ_UI64(P, M, V)						\do {									\    Uint64 v__ = (Uint64) (V);						\    if (v__ >= (((Uint64) 1) << 32)) {					\	if (v__ >= (((Uint64) 1) << 48)) {				\	    if (v__ >= (((Uint64) 1) << 56)) (M) = 7; else (M) = 6;	\	} else {							\	    if (v__ >= (((Uint64) 1) << 40)) (M) = 5; else (M) = 4;	\	}								\    } else {								\	if (v__ >= (((Uint64) 1) << 16)) {				\	    if (v__ >= (((Uint64) 1) << 24)) (M) = 3; else (M) = 2;	\	} else {							\	    if (v__ >= (((Uint64) 1) << 8)) (M) = 1; else (M) = 0;	\	}								\    }	    								\    switch ((M)) {							\    case 7: *((P)++) = (byte) ((v__ >> 56) & 0xff);			\    case 6: *((P)++) = (byte) ((v__ >> 48) & 0xff);			\    case 5: *((P)++) = (byte) ((v__ >> 40) & 0xff);			\    case 4: *((P)++) = (byte) ((v__ >> 32) & 0xff);			\    case 3: *((P)++) = (byte) ((v__ >> 24) & 0xff);			\    case 2: *((P)++) = (byte) ((v__ >> 16) & 0xff);			\    case 1: *((P)++) = (byte) ((v__ >>  8) & 0xff);			\    case 0: *((P)++) = (byte) ( v__        & 0xff);			\    }									\} while (0)#define PUT_VSZ_UI	PUT_VSZ_UI64#else /* #ifdef ARCH_64 */#define PUT_VSZ_UI	PUT_VSZ_UI32#endif /* #ifdef ARCH_64 */#define MAKE_TBUF_SZ(SZ)						\  (TRACE_BUF_SZ < (SZ)							\   ? (disable_trace(1, "Internal buffer overflow", 0), 0)		\   : (endp - tracep < (SZ) ? send_trace_buffer() : 1))static void disable_trace(int error, char *reason, int eno);static int send_trace_buffer(void);#ifdef DEBUGvoidcheck_alloc_entry(byte *sp, byte *ep,		  byte tag,		  Uint16 ct_no, int ct_no_n,		  Uint16 type, int type_n,		  Uint res, int res_n,		  Uint size, int size_n,		  Uint32 ti,int ti_n);voidcheck_realloc_entry(byte *sp, byte *ep,		    byte tag,		    Uint16 ct_no, int ct_no_n,		    Uint16 type, int type_n,		    Uint res, int res_n,		    Uint ptr, int ptr_n,		    Uint size, int size_n,		    Uint32 ti,int ti_n);voidcheck_free_entry(byte *sp, byte *ep,		 byte tag,		 Uint16 ct_no, int ct_no_n,		 Uint16 t_no, int t_no_n,		 Uint ptr, int ptr_n,		 Uint32 ti,int ti_n);voidcheck_time_inc_entry(byte *sp, byte *ep,		     Uint32 secs, int secs_n,		     Uint32 usecs, int usecs_n);#endifint erts_mtrace_enabled;static erts_sock_t socket_desc;static byte trace_buffer[TRACE_BUF_SZ];static byte *tracep;static byte *endp;static SysTimeval last_tv;#if ERTS_MTRACE_SEGMENT_ID >= ERTS_ALC_A_MIN || ERTS_MTRACE_SEGMENT_ID < 0#error ERTS_MTRACE_SEGMENT_ID >= ERTS_ALC_A_MIN || ERTS_MTRACE_SEGMENT_ID < 0#endifchar* erl_errno_id(int error);#define INVALID_TIME_INC (0xffffffff)static ERTS_INLINE Uint32get_time_inc(void){    Sint32 secs;    Sint32 usecs;    Uint32 res;    SysTimeval tv;    sys_gettimeofday(&tv);    secs = tv.tv_sec - last_tv.tv_sec;    if (tv.tv_usec >= last_tv.tv_usec)	usecs = tv.tv_usec - last_tv.tv_usec;    else {	secs--;	usecs = 1000000 + tv.tv_usec - last_tv.tv_usec;    }    ASSERT(0 <= usecs);    ASSERT(usecs < 1000000);    if (secs < 0) {	/* Clock stepped backwards; we pretend that no time has past. */	res = 0;    }    else if (secs < ERTS_MT_TIME_INC_SECS_MASK) {	res = ((((Uint32) secs) << ERTS_MT_TIME_INC_SECS_SHIFT)	       | (((Uint32) usecs) << ERTS_MT_TIME_INC_USECS_SHIFT));    }    else {	/* Increment too large to fit in a 32-bit integer;	   put a time inc entry in trace ... */	if (MAKE_TBUF_SZ(UI8_SZ + UI16_SZ + 2*UI32_SZ)) {	    byte *hdrp;	    Uint16 hdr;	    int secs_n, usecs_n;	    *(tracep++) = ERTS_MT_TIME_INC_BDY_TAG;	    hdrp = tracep;	    tracep += 2;	    PUT_VSZ_UI32(tracep, secs_n,  secs);	    PUT_VSZ_UI32(tracep, usecs_n, usecs);	    hdr = usecs_n;	    hdr <<= UI32_MSB_EHF_SZ;	    hdr |= secs_n;	    WRITE_UI16(hdrp, hdr);#ifdef DEBUG	    check_time_inc_entry(hdrp-1, tracep,				 (Uint32) secs, secs_n,				 (Uint32) usecs, usecs_n);#endif	    res = 0;	}	else {	    res = INVALID_TIME_INC;	}    }    last_tv = tv;    return res;}static voiddisable_trace(int error, char *reason, int eno){    char *mt_dis = "Memory trace disabled";    char *eno_str;    erts_mtrace_enabled = 0;    erts_sock_close(socket_desc);    socket_desc = ERTS_SOCK_INVALID_SOCKET;    if (eno == 0)	erts_fprintf(stderr, "%s: %s\n", mt_dis, reason);    else {	eno_str = erl_errno_id(eno);	if (strcmp(eno_str, "unknown") == 0)	    erts_fprintf(stderr, "%s: %s: %d\n", mt_dis, reason, eno);	else	    erts_fprintf(stderr, "%s: %s: %s\n", mt_dis, reason, eno_str);    }}static intsend_trace_buffer(void){    ssize_t ssz;    size_t sz;    sz = tracep - trace_buffer;    tracep = trace_buffer;    do {	ssz = erts_sock_send(socket_desc, (void  *) tracep, sz);	if (ssz < 0) {	    int socket_errno = erts_sock_errno();#ifdef EINTR	    if (socket_errno == EINTR)		continue;#endif	    disable_trace(0, "Connection lost", socket_errno);	    return 0;	}	if (ssz > sz) {	    disable_trace(1, "Unexpected error", 0);	    return 0;	}	tracep += ssz;	sz -= ssz;    } while (sz);    tracep = trace_buffer;    return 1;}#if ERTS_ALC_N_MAX >= (1 << 16)#error "Excessively large type numbers"#endifstatic intwrite_trace_header(char *nodename, char *pid, char *hostname){#ifdef DEBUG    byte *startp;#endif    Uint16 entry_sz;    Uint32 flags, n_len, h_len, p_len, hdr_prolog_len;    int i, no, str_len;    const char *str;    struct {	Uint32 gsec;	Uint32 sec;	Uint32 usec;    } start_time;    sys_gettimeofday(&last_tv);    start_time.gsec = (Uint32) (last_tv.tv_sec / 1000000000);    start_time.sec  = (Uint32) (last_tv.tv_sec % 1000000000);    start_time.usec = (Uint32) last_tv.tv_usec;    if (!MAKE_TBUF_SZ(3*UI32_SZ))	return 0;    flags = 0;#ifdef ARCH_64    flags |= ERTS_MT_64_BIT_FLAG;#endif    flags |= ERTS_MT_CRR_INFO;#ifdef ERTS_CAN_TRACK_MALLOC    flags |= ERTS_MT_SEG_CRR_INFO;#endif    /*     * The following 3 ui32 words *always* have to come     * first in the trace.     */    PUT_UI32(tracep, ERTS_MT_START_WORD);    PUT_UI32(tracep, ERTS_MT_MAJOR_VSN);    PUT_UI32(tracep, ERTS_MT_MINOR_VSN);    n_len = strlen(nodename);    h_len = strlen(hostname);    p_len = strlen(pid);    hdr_prolog_len = (2*UI32_SZ		      + 3*UI16_SZ		      + 3*UI32_SZ		      + 3*UI8_SZ		      + n_len		      + h_len		      + p_len);    if (!MAKE_TBUF_SZ(hdr_prolog_len))	return 0;    /*     * New stuff can be added at the end the of header prolog     * (EOHP). The reader should skip stuff at the end, that it     * doesn't understand.     */#ifdef DEBUG    startp = tracep;#endif    PUT_UI32(tracep, hdr_prolog_len);    PUT_UI32(tracep, flags);    PUT_UI16(tracep, ERTS_MTRACE_SEGMENT_ID);    PUT_UI16(tracep, ERTS_ALC_A_MAX);    PUT_UI16(tracep, ERTS_ALC_N_MAX);    PUT_UI32(tracep, start_time.gsec);    PUT_UI32(tracep, start_time.sec);    PUT_UI32(tracep, start_time.usec);    PUT_UI8(tracep, (byte) n_len);    memcpy((void *) tracep, (void *) nodename, n_len);    tracep += n_len;    PUT_UI8(tracep, (byte) h_len);    memcpy((void *) tracep, (void *) hostname, h_len);    tracep += h_len;    PUT_UI8(tracep, (byte) p_len);    memcpy((void *) tracep, (void *) pid, p_len);    tracep += p_len;    ASSERT(startp + hdr_prolog_len == tracep);    /*     * EOHP     */    /*     * All tags from here on should be followed by an Uint16 size     * field containing the total size of the entry.     *     * New stuff can eigther be added at the end of an entry, or     * as a new tagged entry. The reader should skip stuff at the     * end, that it doesn't understand.     */    for (i = ERTS_ALC_A_MIN; i <= ERTS_ALC_A_MAX; i++) {	Uint16 aflags = 0;#ifndef ERTS_CAN_TRACK_MALLOC	if (i != ERTS_ALC_A_SYSTEM)#endif	    aflags |= ERTS_MT_ALLCTR_USD_CRR_INFO;	str = ERTS_ALC_A2AD(i);	ASSERT(str);	str_len = strlen(str);	if (str_len >= (1 << 8)) {	    disable_trace(1, "Excessively large allocator string", 0);	    return 0;	}	entry_sz = UI8_SZ + 3*UI16_SZ + UI8_SZ;	entry_sz += (erts_allctrs_info[i].alloc_util ? 2 : 1)*UI16_SZ;	entry_sz += UI8_SZ + str_len;	if (!MAKE_TBUF_SZ(entry_sz))	    return 0;#ifdef DEBUG	startp = tracep;#endif	PUT_UI8(tracep, ERTS_MT_ALLOCATOR_HDR_TAG);	PUT_UI16(tracep, entry_sz);	PUT_UI16(tracep, aflags);	PUT_UI16(tracep, (Uint16) i);	PUT_UI8( tracep, (byte) str_len);	memcpy((void *) tracep, (void *) str, str_len);	tracep += str_len;	if (erts_allctrs_info[i].alloc_util) {	    PUT_UI8(tracep, 2);	    PUT_UI16(tracep, ERTS_MTRACE_SEGMENT_ID);	    PUT_UI16(tracep, ERTS_ALC_A_SYSTEM);	}	else {	    PUT_UI8(tracep, 1);	    switch (i) {	    case ERTS_ALC_A_SYSTEM:		PUT_UI16(tracep, ERTS_MTRACE_SEGMENT_ID);		break;	    case ERTS_ALC_A_FIXED_SIZE:		if (erts_allctrs_info[ERTS_FIX_CORE_ALLOCATOR].enabled)		    PUT_UI16(tracep, ERTS_FIX_CORE_ALLOCATOR);		else		    PUT_UI16(tracep, ERTS_ALC_A_SYSTEM);		break;	    default:		PUT_UI16(tracep, ERTS_MTRACE_SEGMENT_ID);		break;	    }	}	ASSERT(startp + entry_sz == tracep);    }    for (i = ERTS_ALC_N_MIN; i <= ERTS_ALC_N_MAX; i++) {	Uint16 nflags = 0;	str = ERTS_ALC_N2TD(i);	ASSERT(str);	str_len = strlen(str);	if (str_len >= (1 << 8)) {	    disable_trace(1, "Excessively large type string", 0);	    return 0;	}	no = ERTS_ALC_T2A(ERTS_ALC_N2T(i));	if (!erts_allctrs_info[no].enabled)	    no = ERTS_ALC_A_SYSTEM;	ASSERT(ERTS_ALC_A_MIN <= no && no <= ERTS_ALC_A_MAX);	entry_sz = UI8_SZ + 3*UI16_SZ + UI8_SZ + str_len + UI16_SZ;	if (!MAKE_TBUF_SZ(entry_sz))	    return 0;#ifdef DEBUG	startp = tracep;#endif	PUT_UI8(tracep, ERTS_MT_BLOCK_TYPE_HDR_TAG);	PUT_UI16(tracep, entry_sz);	PUT_UI16(tracep, nflags);	PUT_UI16(tracep, (Uint16) i);	PUT_UI8(tracep, (byte) str_len);	memcpy((void *) tracep, (void *) str, str_len);	tracep += str_len;	PUT_UI16(tracep, no);	ASSERT(startp + entry_sz == tracep);    }    entry_sz = UI8_SZ + UI16_SZ;    if (!MAKE_TBUF_SZ(entry_sz))	return 0;    PUT_UI8(tracep, ERTS_MT_END_OF_HDR_TAG);    PUT_UI16(tracep, entry_sz);    return 1;}static void *mtrace_alloc(ErtsAlcType_t, void *, Uint);static void *mtrace_realloc(ErtsAlcType_t, void *, void *, Uint);static void mtrace_free(ErtsAlcType_t, void *, void *);static ErtsAllocatorFunctions_t real_allctrs[ERTS_ALC_A_MAX+1];void erts_mtrace_pre_init(void){}void erts_mtrace_init(char *receiver, char *nodename){    char hostname[MAXHOSTNAMELEN];    char pid[21]; /* enough for a 64 bit number */    socket_desc = ERTS_SOCK_INVALID_SOCKET;    erts_mtrace_enabled = receiver != NULL;    if (erts_mtrace_enabled) {	unsigned a, b, c, d, p;	byte ip_addr[4];	Uint16 port;	erts_mtx_init(&mtrace_buf_mutex, "mtrace_buf");	erts_mtx_set_forksafe(&mtrace_buf_mutex);	erts_mtx_init(&mtrace_op_mutex, "mtrace_op");	erts_mtx_set_forksafe(&mtrace_op_mutex);	socket_desc = erts_sock_open();	if (socket_desc == ERTS_SOCK_INVALID_SOCKET) {	    disable_trace(1, "Failed to open socket", erts_sock_errno());	    return;	}	if (5 != sscanf(receiver, "%u.%u.%u.%u:%u", &a, &b, &c, &d, &p)	    || a >= (1 << 8) || b >= (1 << 8)|| c >= (1 << 8) || d >= (1 << 8)	    || p >= (1 << 16)) {	    disable_trace(1, "Invalid receiver address", 0);	    return;	}	ip_addr[0] = (byte) a;	ip_addr[1] = (byte) b;	ip_addr[2] = (byte) c;	ip_addr[3] = (byte) d; 	port = (Uint16) p;	if (!erts_sock_connect(socket_desc, ip_addr, 4, port)) {	    disable_trace(1, "Failed to connect to receiver",			  erts_sock_errno());	    return;	}	tracep = trace_buffer;	endp = trace_buffer + TRACE_BUF_SZ;	if (erts_sock_gethostname(hostname, MAXHOSTNAMELEN) != 0)	    hostname[0] = '\0';	hostname[MAXHOSTNAMELEN-1] = '\0';

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -