Why our autobuilds fail

Jeremy Allison jra at samba.org
Wed Mar 4 11:58:23 MST 2015


On Mon, Mar 02, 2015 at 05:29:25PM +0100, Stefan (metze) Metzmacher wrote:
> Hi,
> 
> > Oh my goodness, we still use SYSV shared memory somewhere ? !!!!
> > 
> > Thought we'd removed that many years ago :-).
> > 
> >> Metze, can we get
> >> https://git.samba.org/?p=metze/samba/wip.git;a=commitdiff;h=25ee2483ce3d887d53f72086
> >> on the car pool lane? :-)
> 
> Here're it is...
> 
> I plan to push this tomorrow, if there're no objections.

Please push this ! :-).

> From 166d671137d9a1a5495115cee2e5f9ffc8fa9f04 Mon Sep 17 00:00:00 2001
> From: Stefan Metzmacher <metze at samba.org>
> Date: Fri, 28 Nov 2014 09:33:13 +0100
> Subject: [PATCH 1/7] s3:smbprofile: specify SMBPROFILE_STATS_SECTION_START()
>  with name vs. display[name]
> 
> Signed-off-by: Stefan Metzmacher <metze at samba.org>
> Reviewed-by: Volker Lendecke <vl at samba.org>
> Reviewed-by: Ralph Boehme <slow at samba.org>
> ---
>  source3/include/smbprofile.h   | 20 ++++++++++----------
>  source3/utils/status_profile.c |  4 ++--
>  2 files changed, 12 insertions(+), 12 deletions(-)
> 
> diff --git a/source3/include/smbprofile.h b/source3/include/smbprofile.h
> index ea24165..bf2b3b4 100644
> --- a/source3/include/smbprofile.h
> +++ b/source3/include/smbprofile.h
> @@ -26,7 +26,7 @@
>  #define SMBPROFILE_STATS_ALL_SECTIONS \
>  	SMBPROFILE_STATS_START \
>  	\
> -	SMBPROFILE_STATS_SECTION_START("SMBD loop") \
> +	SMBPROFILE_STATS_SECTION_START(global, "SMBD loop") \
>  	SMBPROFILE_STATS_COUNT(connect) \
>  	SMBPROFILE_STATS_COUNT(disconnect) \
>  	SMBPROFILE_STATS_BASIC(idle) \
> @@ -37,7 +37,7 @@
>  	SMBPROFILE_STATS_BASIC(pop_sec_ctx) \
>  	SMBPROFILE_STATS_SECTION_END \
>  	\
> -	SMBPROFILE_STATS_SECTION_START("System Calls") \
> +	SMBPROFILE_STATS_SECTION_START(syscall, "System Calls") \
>  	SMBPROFILE_STATS_BASIC(syscall_opendir) \
>  	SMBPROFILE_STATS_BASIC(syscall_fdopendir) \
>  	SMBPROFILE_STATS_BASIC(syscall_readdir) \
> @@ -96,7 +96,7 @@
>  	SMBPROFILE_STATS_BASIC(syscall_brl_cancel) \
>  	SMBPROFILE_STATS_SECTION_END \
>  	\
> -	SMBPROFILE_STATS_SECTION_START("ACL Calls") \
> +	SMBPROFILE_STATS_SECTION_START(acl, "ACL Calls") \
>  	SMBPROFILE_STATS_BASIC(get_nt_acl) \
>  	SMBPROFILE_STATS_BASIC(fget_nt_acl) \
>  	SMBPROFILE_STATS_BASIC(fset_nt_acl) \
> @@ -104,13 +104,13 @@
>  	SMBPROFILE_STATS_BASIC(fchmod_acl) \
>  	SMBPROFILE_STATS_SECTION_END \
>  	\
> -	SMBPROFILE_STATS_SECTION_START("Stat Cache") \
> +	SMBPROFILE_STATS_SECTION_START(statcache, "Stat Cache") \
>  	SMBPROFILE_STATS_COUNT(statcache_lookups) \
>  	SMBPROFILE_STATS_COUNT(statcache_misses) \
>  	SMBPROFILE_STATS_COUNT(statcache_hits) \
>  	SMBPROFILE_STATS_SECTION_END \
>  	\
> -	SMBPROFILE_STATS_SECTION_START("Write Cache") \
> +	SMBPROFILE_STATS_SECTION_START(writecache, "Write Cache") \
>  	SMBPROFILE_STATS_COUNT(writecache_allocations) \
>  	SMBPROFILE_STATS_COUNT(writecache_deallocations) \
>  	SMBPROFILE_STATS_COUNT(writecache_cached_reads) \
> @@ -131,7 +131,7 @@
>  	SMBPROFILE_STATS_COUNT(writecache_flush_reason_sizechange) \
>  	SMBPROFILE_STATS_SECTION_END \
>  	\
> -	SMBPROFILE_STATS_SECTION_START("SMB Calls") \
> +	SMBPROFILE_STATS_SECTION_START(SMB, "SMB Calls") \
>  	SMBPROFILE_STATS_BASIC(SMBmkdir) \
>  	SMBPROFILE_STATS_BASIC(SMBrmdir) \
>  	SMBPROFILE_STATS_BASIC(SMBopen) \
> @@ -209,7 +209,7 @@
>  	SMBPROFILE_STATS_BASIC(SMBinvalid) \
>  	SMBPROFILE_STATS_SECTION_END \
>  	\
> -	SMBPROFILE_STATS_SECTION_START("Trans2 Calls") \
> +	SMBPROFILE_STATS_SECTION_START(Trans2, "Trans2 Calls") \
>  	SMBPROFILE_STATS_BASIC(Trans2_open) \
>  	SMBPROFILE_STATS_BASIC(Trans2_findfirst) \
>  	SMBPROFILE_STATS_BASIC(Trans2_findnext) \
> @@ -229,7 +229,7 @@
>  	SMBPROFILE_STATS_BASIC(Trans2_report_dfs_inconsistancy) \
>  	SMBPROFILE_STATS_SECTION_END \
>  	\
> -	SMBPROFILE_STATS_SECTION_START("NT Transact Calls") \
> +	SMBPROFILE_STATS_SECTION_START(NT_transact, "NT Transact Calls") \
>  	SMBPROFILE_STATS_BASIC(NT_transact_create) \
>  	SMBPROFILE_STATS_BASIC(NT_transact_ioctl) \
>  	SMBPROFILE_STATS_BASIC(NT_transact_set_security_desc) \
> @@ -240,7 +240,7 @@
>  	SMBPROFILE_STATS_BASIC(NT_transact_set_user_quota) \
>  	SMBPROFILE_STATS_SECTION_END \
>  	\
> -	SMBPROFILE_STATS_SECTION_START("SMB2 Calls") \
> +	SMBPROFILE_STATS_SECTION_START(smb2, "SMB2 Calls") \
>  	SMBPROFILE_STATS_IOBYTES(smb2_negprot) \
>  	SMBPROFILE_STATS_IOBYTES(smb2_sesssetup) \
>  	SMBPROFILE_STATS_IOBYTES(smb2_logoff) \
> @@ -323,7 +323,7 @@ struct smbprofile_stats_iobytes_async {
>  
>  struct profile_stats {
>  #define SMBPROFILE_STATS_START
> -#define SMBPROFILE_STATS_SECTION_START(name)
> +#define SMBPROFILE_STATS_SECTION_START(name, display)
>  #define SMBPROFILE_STATS_COUNT(name) \
>  	struct smbprofile_stats_count name##_stats;
>  #define SMBPROFILE_STATS_TIME(name) \
> diff --git a/source3/utils/status_profile.c b/source3/utils/status_profile.c
> index f0cf405..a0f98d8 100644
> --- a/source3/utils/status_profile.c
> +++ b/source3/utils/status_profile.c
> @@ -53,7 +53,7 @@ bool status_profile_dump(bool verbose)
>  		 (uintmax_t)profile_p->_stats.field); \
>  } while(0);
>  #define SMBPROFILE_STATS_START
> -#define SMBPROFILE_STATS_SECTION_START(name) profile_separator(#name);
> +#define SMBPROFILE_STATS_SECTION_START(name, display) profile_separator(#display);
>  #define SMBPROFILE_STATS_COUNT(name) do { \
>  	__PRINT_FIELD_LINE(#name, name##_stats,  count); \
>  } while(0);
> @@ -243,7 +243,7 @@ static uint64_t print_count_samples(
>  	}
>  
>  #define SMBPROFILE_STATS_START
> -#define SMBPROFILE_STATS_SECTION_START(name)
> +#define SMBPROFILE_STATS_SECTION_START(name, display)
>  #define SMBPROFILE_STATS_COUNT(name) do { \
>  	count += print_count_count_samples(buf, sizeof(buf), \
>  					   #name, \
> -- 
> 1.9.1
> 
> 
> From 5250c4ddecf57e5be7b77d2ddf345f1356755ee9 Mon Sep 17 00:00:00 2001
> From: Stefan Metzmacher <metze at samba.org>
> Date: Wed, 3 Dec 2014 12:35:00 +0100
> Subject: [PATCH 2/7] s3:smbstatus: Implement -P --prompt
> 
> This is intended to do continuous perfcount output when being asked and
> when fork/exec is too expensive.
> 
> Pair-Programmed-With: Volker Lendecke <vl at samba.org>
> 
> Signed-off-by: Stefan Metzmacher <metze at samba.org>
> Signed-off-by: Volker Lendecke <vl at samba.org>
> Reviewed-by: Ralph Boehme <slow at samba.org>
> ---
>  docs-xml/manpages/smbstatus.1.xml    |   9 +
>  source3/utils/status.c               |   6 +
>  source3/utils/status_profile.c       | 482 +++++++++++++++++++++++++++++++++++
>  source3/utils/status_profile.h       |   1 +
>  source3/utils/status_profile_dummy.c |   5 +
>  5 files changed, 503 insertions(+)
> 
> diff --git a/docs-xml/manpages/smbstatus.1.xml b/docs-xml/manpages/smbstatus.1.xml
> index 4037713..3527698 100644
> --- a/docs-xml/manpages/smbstatus.1.xml
> +++ b/docs-xml/manpages/smbstatus.1.xml
> @@ -33,6 +33,7 @@
>  		<arg choice="opt">-u <username></arg>
>  		<arg choice="opt">-n|--numeric</arg>
>  		<arg choice="opt">-R|--profile-rates</arg>
> +		<arg choice="opt">--prompt</arg>
>  	</cmdsynopsis>
>  </refsynopsisdiv>
>  
> @@ -58,6 +59,14 @@
>  		</varlistentry>
>  
>  		<varlistentry>
> +		<term>--prompt</term>
> +		<listitem><para>If samba has been compiled with the profiling
> +		option, open an interactive command prompt, providing various
> +		commands for accessing the profiling data. Typing any invalid
> +		command will show the available commands.</para></listitem>
> +		</varlistentry>
> +
> +		<varlistentry>
>  		<term>-R|--profile-rates</term>
>  		<listitem><para>If samba has been compiled with the
>  		profiling option, print the contents of the profiling
> diff --git a/source3/utils/status.c b/source3/utils/status.c
> index 61efa93..c12d09c 100644
> --- a/source3/utils/status.c
> +++ b/source3/utils/status.c
> @@ -349,6 +349,7 @@ int main(int argc, const char *argv[])
>  {
>  	int c;
>  	int profile_only = 0;
> +	int prompt = 0;
>  	bool show_processes, show_locks, show_shares;
>  	bool show_notify = false;
>  	poptContext pc;
> @@ -362,6 +363,8 @@ int main(int argc, const char *argv[])
>  		{"user", 	'u', POPT_ARG_STRING,	&username, 'u', "Switch to user" },
>  		{"brief",	'b', POPT_ARG_NONE, 	NULL, 'b', "Be brief" },
>  		{"profile",     'P', POPT_ARG_NONE, NULL, 'P', "Do profiling" },
> +		{"prompt",	0,   POPT_ARG_NONE, &prompt, 0,
> +		 "Interactive profiling info" },
>  		{"profile-rates", 'R', POPT_ARG_NONE, NULL, 'R', "Show call rates" },
>  		{"byterange",	'B', POPT_ARG_NONE,	NULL, 'B', "Include byte range locks"},
>  		{"numeric",	'n', POPT_ARG_NONE,	NULL, 'n', "Numeric uid/gid"},
> @@ -479,6 +482,9 @@ int main(int argc, const char *argv[])
>  
>  	switch (profile_only) {
>  		case 'P':
> +			if (prompt) {
> +				return status_profile_prompt();
> +			}
>  			/* Dump profile data */
>  			ok = status_profile_dump(verbose);
>  			return ok ? 0 : 1;
> diff --git a/source3/utils/status_profile.c b/source3/utils/status_profile.c
> index a0f98d8..79c5197 100644
> --- a/source3/utils/status_profile.c
> +++ b/source3/utils/status_profile.c
> @@ -21,6 +21,7 @@
>  #include "includes.h"
>  #include "smbprofile.h"
>  #include "status_profile.h"
> +#include "popt_common.h"
>  
>  static void profile_separator(const char * title)
>  {
> @@ -357,3 +358,484 @@ bool status_profile_rates(bool verbose)
>  
>  	return True;
>  }
> +
> +struct status_profile_prompt_state {
> +	struct {
> +		TALLOC_CTX *frame;
> +		int argc;
> +		const char **argv;
> +		poptContext pc;
> +		const char *orig_cmd;
> +		const char *cmd;
> +		bool do_exit;
> +		int exit_code;
> +	} tmp;
> +
> +	struct {
> +		const char *format;
> +		const char *_sections;
> +		const char **sections;
> +		const char *_fields;
> +		bool field_count;
> +		bool field_time;
> +		bool field_idle;
> +		bool field_bytes;
> +		bool field_inbytes;
> +		bool field_outbytes;
> +	} output;
> +};
> +
> +static int status_profile_prompt_options(struct status_profile_prompt_state *state)
> +{
> +	const char **fields = NULL;
> +
> +	if (state->output.format == NULL) {
> +		state->output.format = "";
> +	}
> +
> +	if (strcmp(state->output.format, "oneline-function") == 0) {
> +	} else if (strcmp(state->output.format, "oneline-section") == 0) {
> +	} else {
> +		d_printf("ERROR: %s: invalid format[%s]\n",
> +			 state->tmp.cmd, state->output.format);
> +		return -1;
> +	}
> +
> +	if (state->output._sections != NULL) {
> +		char **s;
> +
> +		s = str_list_make(state->tmp.frame,
> +				  state->output._sections,
> +				  ",");
> +		if (s == NULL) {
> +			return -1;
> +		}
> +		state->output.sections = discard_const_p(const char *, s);
> +	}
> +
> +	if (state->output._fields != NULL) {
> +		char **s;
> +
> +		s = str_list_make(state->tmp.frame,
> +				  state->output._fields,
> +				  ",");
> +		if (s == NULL) {
> +			return -1;
> +		}
> +		fields = discard_const_p(const char *, s);
> +	}
> +
> +	if (fields == NULL) {
> +		state->output.field_count = true;
> +		state->output.field_time = true;
> +		state->output.field_idle = true;
> +		state->output.field_bytes = true;
> +		state->output.field_inbytes = true;
> +		state->output.field_outbytes = true;
> +	}
> +	if (str_list_check(fields, "count")) {
> +		state->output.field_count = true;
> +	}
> +	if (str_list_check(fields, "time")) {
> +		state->output.field_time = true;
> +	}
> +	if (str_list_check(fields, "idle")) {
> +		state->output.field_idle = true;
> +	}
> +	if (str_list_check(fields, "bytes")) {
> +		state->output.field_bytes = true;
> +	}
> +	if (str_list_check(fields, "inbytes")) {
> +		state->output.field_inbytes = true;
> +	}
> +	if (str_list_check(fields, "outbytes")) {
> +		state->output.field_outbytes = true;
> +	}
> +
> +	TALLOC_FREE(fields);
> +	return 0;
> +}
> +
> +static int status_profile_accumulated(struct status_profile_prompt_state *state)
> +{
> +	if (strcmp(state->output.format, "oneline-function") == 0) {
> +#define SMBPROFILE_STATS_START \
> +	d_printf("_response_ begin accumulated\n");
> +#define SMBPROFILE_STATS_SECTION_START(name, display) do { \
> +	if (state->output.sections == NULL || \
> +	    str_list_check(state->output.sections, #name)) \
> +	{ \
> +		const char *__section = #name; \
> +		size_t __len = strlen(__section); \
> +		d_printf("_section_ begin %s\n", __section);
> +#define __PREPARE_FIELD_NAME(name) \
> +	const char *__n = name; \
> +	int __cmp; \
> +	__cmp = strncmp(__section, __n, __len); \
> +	if (__cmp == 0) { \
> +		__n += __len; \
> +		if (__n[0] == '_') { \
> +			__n += 1; \
> +		} \
> +	}
> +#define __PRINT_FIELD_LINE(__s, __f) \
> +	if (state->output.field_##__f) { \
> +		d_printf(" _%s_ %ju", \
> +			 #__f, \
> +			 (uintmax_t)(profile_p->__s.__f)); \
> +	}
> +#define SMBPROFILE_STATS_COUNT(name) do { \
> +	if (state->output.field_count) { \
> +		__PREPARE_FIELD_NAME(#name) \
> +		d_printf("%s:", __n); \
> +		__PRINT_FIELD_LINE(name##_stats, count) \
> +		d_printf("\n"); \
> +	} \
> +} while(0);
> +#define SMBPROFILE_STATS_TIME(name) do { \
> +	if (state->output.field_time) { \
> +		__PREPARE_FIELD_NAME(#name) \
> +		d_printf("%s:", __n); \
> +		__PRINT_FIELD_LINE(name##_stats, time) \
> +		d_printf("\n"); \
> +	} \
> +} while(0);
> +#define SMBPROFILE_STATS_BASIC(name) do { \
> +	if (state->output.field_count || \
> +	    state->output.field_time) \
> +	{ \
> +		__PREPARE_FIELD_NAME(#name) \
> +		d_printf("%s:", __n); \
> +		__PRINT_FIELD_LINE(name##_stats, count) \
> +		__PRINT_FIELD_LINE(name##_stats, time) \
> +		d_printf("\n"); \
> +	} \
> +} while(0);
> +#define SMBPROFILE_STATS_BYTES(name) do { \
> +	if (state->output.field_count || \
> +	    state->output.field_time || \
> +	    state->output.field_idle || \
> +	    state->output.field_bytes) \
> +	{ \
> +		__PREPARE_FIELD_NAME(#name) \
> +		d_printf("%s:", __n); \
> +		__PRINT_FIELD_LINE(name##_stats, count) \
> +		__PRINT_FIELD_LINE(name##_stats, time) \
> +		__PRINT_FIELD_LINE(name##_stats, idle) \
> +		__PRINT_FIELD_LINE(name##_stats, bytes) \
> +		d_printf("\n"); \
> +	} \
> +} while(0);
> +#define SMBPROFILE_STATS_IOBYTES(name) do { \
> +	if (state->output.field_count || \
> +	    state->output.field_time || \
> +	    state->output.field_idle || \
> +	    state->output.field_inbytes || \
> +	    state->output.field_outbytes) \
> +	{ \
> +		__PREPARE_FIELD_NAME(#name) \
> +		d_printf("%s:", __n); \
> +		__PRINT_FIELD_LINE(name##_stats, count) \
> +		__PRINT_FIELD_LINE(name##_stats, time) \
> +		__PRINT_FIELD_LINE(name##_stats, idle) \
> +		__PRINT_FIELD_LINE(name##_stats, inbytes) \
> +		__PRINT_FIELD_LINE(name##_stats, outbytes) \
> +		d_printf("\n"); \
> +	} \
> +} while(0);
> +#define SMBPROFILE_STATS_SECTION_END \
> +		d_printf("_section_ end\n"); \
> +	} \
> +} while(0);
> +#define SMBPROFILE_STATS_END \
> +	d_printf("_response_ end\n");
> +	SMBPROFILE_STATS_ALL_SECTIONS
> +#undef SMBPROFILE_STATS_START
> +#undef SMBPROFILE_STATS_SECTION_START
> +#undef __PRINT_FIELD_LINE
> +#undef SMBPROFILE_STATS_COUNT
> +#undef SMBPROFILE_STATS_TIME
> +#undef SMBPROFILE_STATS_BASIC
> +#undef SMBPROFILE_STATS_BYTES
> +#undef SMBPROFILE_STATS_IOBYTES
> +#undef SMBPROFILE_STATS_SECTION_END
> +#undef SMBPROFILE_STATS_END
> +	} else if (strcmp(state->output.format, "oneline-section") == 0) {
> +#define SMBPROFILE_STATS_START \
> +	d_printf("_response_ begin accumulated\n");
> +#define SMBPROFILE_STATS_SECTION_START(name, display) do { \
> +	if (state->output.sections == NULL || \
> +	    str_list_check(state->output.sections, #name)) \
> +	{ \
> +		const char *__section = #name; \
> +		size_t __len = strlen(__section); \
> +		d_printf("%s:", __section);
> +#define __PREPARE_FIELD_NAME(name) \
> +	const char *__n = name; \
> +	int __cmp; \
> +	__cmp = strncmp(__section, __n, __len); \
> +	if (__cmp == 0) { \
> +		__n += __len; \
> +		if (__n[0] == '_') { \
> +			__n += 1; \
> +		} \
> +	}
> +#define __PRINT_FIELD_LINE(__s, __f) \
> +	if (state->output.field_##__f) { \
> +		d_printf(" _%s_%s_ %ju", \
> +			 __n, #__f, \
> +			 (uintmax_t)(profile_p->__s.__f)); \
> +	}
> +#define SMBPROFILE_STATS_COUNT(name) do { \
> +	__PREPARE_FIELD_NAME(#name) \
> +	__PRINT_FIELD_LINE(name##_stats, count) \
> +} while(0);
> +#define SMBPROFILE_STATS_TIME(name) do { \
> +	__PREPARE_FIELD_NAME(#name) \
> +	__PRINT_FIELD_LINE(name##_stats, time) \
> +} while(0);
> +#define SMBPROFILE_STATS_BASIC(name) do { \
> +	__PREPARE_FIELD_NAME(#name) \
> +	__PRINT_FIELD_LINE(name##_stats, count) \
> +	__PRINT_FIELD_LINE(name##_stats, time) \
> +} while(0);
> +#define SMBPROFILE_STATS_BYTES(name) do { \
> +	__PREPARE_FIELD_NAME(#name) \
> +	__PRINT_FIELD_LINE(name##_stats, count) \
> +	__PRINT_FIELD_LINE(name##_stats, time) \
> +	__PRINT_FIELD_LINE(name##_stats, idle) \
> +	__PRINT_FIELD_LINE(name##_stats, bytes) \
> +} while(0);
> +#define SMBPROFILE_STATS_IOBYTES(name) do { \
> +	__PREPARE_FIELD_NAME(#name) \
> +	__PRINT_FIELD_LINE(name##_stats, count) \
> +	__PRINT_FIELD_LINE(name##_stats, time) \
> +	__PRINT_FIELD_LINE(name##_stats, idle) \
> +	__PRINT_FIELD_LINE(name##_stats, inbytes) \
> +	__PRINT_FIELD_LINE(name##_stats, outbytes) \
> +} while(0);
> +#define SMBPROFILE_STATS_SECTION_END \
> +		d_printf("\n"); \
> +	} \
> +} while(0);
> +#define SMBPROFILE_STATS_END \
> +	d_printf("_response_ end\n");
> +	SMBPROFILE_STATS_ALL_SECTIONS
> +#undef SMBPROFILE_STATS_START
> +#undef SMBPROFILE_STATS_SECTION_START
> +#undef __PREPARE_FIELD_NAME
> +#undef __PRINT_FIELD_LINE
> +#undef SMBPROFILE_STATS_COUNT
> +#undef SMBPROFILE_STATS_TIME
> +#undef SMBPROFILE_STATS_BASIC
> +#undef SMBPROFILE_STATS_BYTES
> +#undef SMBPROFILE_STATS_IOBYTES
> +#undef SMBPROFILE_STATS_SECTION_END
> +#undef SMBPROFILE_STATS_END
> +	} else {
> +		d_printf("ERROR: %s: invalid format[%s]\n",
> +			 state->tmp.cmd, state->output.format);
> +		return -1;
> +	}
> +
> +	return 0;
> +}
> +
> +static int status_profile_prompt_exit(struct status_profile_prompt_state *state)
> +{
> +	state->tmp.do_exit = true;
> +	state->tmp.exit_code = 0;
> +	return 0;
> +}
> +
> +int status_profile_prompt(void)
> +{
> +	struct status_profile_prompt_state state = {};
> +	const char *_error_argv[] = { "usage", NULL };
> +	const char *_default_format = "oneline-function";
> +	const struct {
> +		const char *name;
> +		bool options;
> +		int (*fn)(struct status_profile_prompt_state *state);
> +	} cmds[] = {
> +	{
> +		.name = "get-accumulated",
> +		.options = true,
> +		.fn = status_profile_accumulated,
> +	},
> +	{
> +		.name = "exit",
> +		.fn = status_profile_prompt_exit,
> +	},
> +	};
> +	const struct poptOption options[] = {
> +		{ "format", 0,
> +		 POPT_ARG_STRING|POPT_ARGFLAG_SHOW_DEFAULT|POPT_ARGFLAG_OPTIONAL,
> +		 &state.output.format, 0, "output format",
> +		 "oneline-function,oneline-section",
> +		},
> +		{"sections", 0,
> +		 POPT_ARG_STRING|POPT_ARGFLAG_OPTIONAL,
> +		 &state.output._sections, 0, "print only the given sections",
> +		 ""
> +#define SMBPROFILE_STATS_START
> +#define SMBPROFILE_STATS_SECTION_START(name, display) #name
> +#define SMBPROFILE_STATS_COUNT(name)
> +#define SMBPROFILE_STATS_TIME(name)
> +#define SMBPROFILE_STATS_BASIC(name)
> +#define SMBPROFILE_STATS_BYTES(name)
> +#define SMBPROFILE_STATS_IOBYTES(name)
> +#define SMBPROFILE_STATS_SECTION_END ","
> +#define SMBPROFILE_STATS_END
> +	SMBPROFILE_STATS_ALL_SECTIONS
> +#undef SMBPROFILE_STATS_START
> +#undef SMBPROFILE_STATS_SECTION_START
> +#undef SMBPROFILE_STATS_COUNT
> +#undef SMBPROFILE_STATS_TIME
> +#undef SMBPROFILE_STATS_BASIC
> +#undef SMBPROFILE_STATS_BYTES
> +#undef SMBPROFILE_STATS_IOBYTES
> +#undef SMBPROFILE_STATS_SECTION_END
> +#undef SMBPROFILE_STATS_END
> +		},
> +		{ "fields", 0,
> +		 POPT_ARG_STRING|POPT_ARGFLAG_OPTIONAL,
> +		 &state.output._fields, 0, "print only the given fields",
> +		 "count,time,idle,bytes,inbytes,outbytes",
> +		},
> +		{ NULL, 0, 0, NULL, 0 }
> +	};
> +
> +	if (!profile_setup(NULL, true)) {
> +		fprintf(stderr,"Failed to initialise profile memory\n");
> +		return 1;
> +	}
> +
> +	while (1) {
> +		char line[4096] = {};
> +		const char *next = NULL;
> +		int ret;
> +		int idx;
> +
> +		/*
> +		 * This is designed to be called via a pipe, so we need
> +		 * to explictly flush before/after each command.
> +		 */
> +		fflush(stdout);
> +		fflush(stderr);
> +
> +		if (state.tmp.pc != NULL) {
> +			poptFreeContext(state.tmp.pc);
> +		}
> +		if (state.tmp.argv != _error_argv) {
> +			char **a = discard_const_p(char *, state.tmp.argv);
> +			SAFE_FREE(a);
> +		}
> +		TALLOC_FREE(state.tmp.frame);
> +		if (state.output.format != _default_format) {
> +			char *f = discard_const_p(char, state.output.format);
> +			SAFE_FREE(f);
> +		}
> +
> +		if (state.tmp.do_exit) {
> +			return state.tmp.exit_code;
> +		}
> +
> +		ZERO_STRUCT(state.tmp);
> +		ZERO_STRUCT(state.output);
> +
> +		state.tmp.frame = talloc_stackframe();
> +		state.tmp.cmd = "";
> +		state.output.format = _default_format;
> +
> +		if (fgets(line, sizeof(line), stdin) == NULL) {
> +			state.tmp.do_exit = true;
> +			state.tmp.exit_code = 1;
> +			continue;
> +		}
> +
> +		ret = poptParseArgvString(line, &state.tmp.argc,
> +					  &state.tmp.argv);
> +		if (ret != 0) {
> +			state.tmp.argc = 1;
> +			state.tmp.argv = _error_argv;
> +		}
> +
> +		for (idx=0; idx < ARRAY_SIZE(cmds); idx++) {
> +			if (strcmp(state.tmp.argv[0], cmds[idx].name) != 0) {
> +				continue;
> +			}
> +
> +			state.tmp.cmd = state.tmp.argv[0];
> +			break;
> +		}
> +
> +		state.tmp.orig_cmd = state.tmp.argv[0];
> +		state.tmp.argv[0] = state.tmp.cmd;
> +
> +		state.tmp.pc = poptGetContext(state.tmp.argv[0],
> +					      state.tmp.argc,
> +					      state.tmp.argv,
> +					      options, 0);
> +		if (state.tmp.pc == NULL) {
> +			state.tmp.do_exit = true;
> +			state.tmp.exit_code = 2;
> +			continue;
> +		}
> +
> +		while ((ret = poptGetNextOpt(state.tmp.pc)) >= 0) { }
> +		if (ret != -1) {
> +			d_printf("ERROR: %s: %s(%d) - %s\n",
> +				 state.tmp.cmd, poptStrerror(ret), ret,
> +				 poptBadOption(state.tmp.pc, 0));
> +			state.tmp.do_exit = true;
> +			state.tmp.exit_code = ret;
> +			continue;
> +		}
> +
> +		next = poptPeekArg(state.tmp.pc);
> +		if (next != NULL) {
> +			d_printf("ERROR: %s: invalid argument[%s]\n",
> +				 state.tmp.cmd, poptBadOption(state.tmp.pc, 0));
> +			state.tmp.do_exit = true;
> +			state.tmp.exit_code = EINVAL;
> +			continue;
> +		}
> +
> +		if (idx < ARRAY_SIZE(cmds)) {
> +			if (cmds[idx].options) {
> +				ret = status_profile_prompt_options(&state);
> +				if (ret != 0) {
> +					state.tmp.do_exit = true;
> +					state.tmp.exit_code = ret;
> +					continue;
> +				}
> +			}
> +
> +			ret = cmds[idx].fn(&state);
> +			if (ret != 0) {
> +				state.tmp.do_exit = true;
> +				state.tmp.exit_code = ret;
> +			}
> +			continue;
> +		}
> +
> +		d_printf("ERROR: invalid command[%s]\npossible commands:\n\n",
> +			 state.tmp.orig_cmd);
> +		for (idx=0; idx < ARRAY_SIZE(cmds); idx++) {
> +			const char *argv[] = { cmds[idx].name, NULL };
> +			poptContext pc;
> +
> +			pc = poptGetContext(argv[0], 1, argv,
> +					    cmds[idx].options ? options : NULL,
> +					    0);
> +			if (!cmds[idx].options) {
> +				poptSetOtherOptionHelp(pc, "");
> +			}
> +			poptPrintHelp(pc, stdout, 0);
> +			poptFreeContext(pc);
> +		}
> +	}
> +
> +	return 1;
> +}
> diff --git a/source3/utils/status_profile.h b/source3/utils/status_profile.h
> index a8a73e1..10a84ae 100644
> --- a/source3/utils/status_profile.h
> +++ b/source3/utils/status_profile.h
> @@ -24,5 +24,6 @@
>  
>  bool status_profile_dump(bool be_verbose);
>  bool status_profile_rates(bool be_verbose);
> +int status_profile_prompt(void);
>  
>  #endif
> diff --git a/source3/utils/status_profile_dummy.c b/source3/utils/status_profile_dummy.c
> index dfc5da7..a16b1a1 100644
> --- a/source3/utils/status_profile_dummy.c
> +++ b/source3/utils/status_profile_dummy.c
> @@ -32,3 +32,8 @@ bool status_profile_rates(bool be_verbose)
>  	fprintf(stderr, "Profile data unavailable\n");
>  	return true;
>  }
> +
> +int status_profile_prompt(void) {
> +	fprintf(stderr, "Profile data unavailable\n");
> +	return -1;
> +}
> -- 
> 1.9.1
> 
> 
> From 36f89e95418dcb6be08def9b311e59ff27b0a2ae Mon Sep 17 00:00:00 2001
> From: Volker Lendecke <vl at samba.org>
> Date: Mon, 29 Sep 2014 16:08:17 +0000
> Subject: [PATCH 3/7] s3:smbprofile: Replace sysv shmem with tdb
> 
> What?
> 
> This patch gets rid of the central shared memory segment referenced by
> "profile_p". Instead, every smbd gets a static profile_area where it collects
> profiling data. Once a second, every smbd writes this profiling data into a
> record of its own in a "smbprofile.tdb". smbstatus -P does a tdb_traverse on this
> database and sums up what it finds.
> 
> Why?
> 
> At least in my perception sysv IPC has not the best reputation on earth. The
> code before this patch uses shmat(). Samba ages ago has developed a good
> abstraction of shared memory: It's called tdb.
> 
> The main reason why I started this is that I have a request to become
> more flexible with profiling data. Samba should be able to collect data
> per share or per user, something which is almost impossible to do with
> a fixed structure. My idea is to for example install a profile area per
> share and every second marshall this into one tdb record indexed by share
> name. smbstatus -P would then also collect the data and either aggregate
> them or put them into individual per-share statistics. This flexibility
> in the data model is not really possible with one fixed structure.
> 
> But isn't it slow?
> 
> Well, I don't think so. I can't really prove it, but I do believe that on large
> boxes atomically incrementing a shared memory value for every SMB does show up
> due to NUMA effects. With this patch the hot code path is completely
> process-local. Once a second every smbd writes into a central tdb, this of
> course does atomic operations. But it's once a second, not on every SMB2 read.
> 
> There's two places where I would like to improve things: With the current code
> all smbds wake up once a second. With 10,000 potentially idle smbds this will
> become noticable. That's why the current only starts the timer when something has
> changed.
> 
> The second place is the tdb traverse: Right now traverse is blocking in the
> sense that when it has to switch hash chains it will block. With mutexes, this
> means a syscall. I have a traverse light in mind that works as follows: It
> assumes a locked hash chain and then walks the complete chain in one run
> without unlocking in between. This way the caller can do nonblocking locks in
> the first round and only do blocking locks in a second round. Also, a lot of
> syscall overhead will vanish. This way smbstatus -P will have almost zero
> impact on normal operations.
> 
> Pair-Programmed-With: Stefan Metzmacher <metze at samba.org>
> 
> Signed-off-by: Volker Lendecke <vl at samba.org>
> Signed-off-by: Stefan Metzmacher <metze at samba.org>
> Reviewed-by: Ralph Boehme <slow at samba.org>
> ---
>  source3/include/smbprofile.h   | 116 +++++++++++--
>  source3/profile/profile.c      | 381 ++++++++++++++++++++++++++++++++---------
>  source3/smbd/process.c         |  25 +++
>  source3/smbd/server.c          |   2 +
>  source3/smbd/server_exit.c     |   2 +
>  source3/smbd/smb2_server.c     |   4 +-
>  source3/utils/status_profile.c |  84 +++++++--
>  7 files changed, 502 insertions(+), 112 deletions(-)
> 
> diff --git a/source3/include/smbprofile.h b/source3/include/smbprofile.h
> index bf2b3b4..b32d938 100644
> --- a/source3/include/smbprofile.h
> +++ b/source3/include/smbprofile.h
> @@ -21,6 +21,8 @@
>  
>  */
>  
> +struct tevent_context;
> +
>  #ifdef WITH_PROFILE
>  
>  #define SMBPROFILE_STATS_ALL_SECTIONS \
> @@ -322,6 +324,8 @@ struct smbprofile_stats_iobytes_async {
>  };
>  
>  struct profile_stats {
> +	uint64_t magic;
> +	struct {
>  #define SMBPROFILE_STATS_START
>  #define SMBPROFILE_STATS_SECTION_START(name, display)
>  #define SMBPROFILE_STATS_COUNT(name) \
> @@ -346,11 +350,13 @@ struct profile_stats {
>  #undef SMBPROFILE_STATS_IOBYTES
>  #undef SMBPROFILE_STATS_SECTION_END
>  #undef SMBPROFILE_STATS_END
> +	} values;
>  };
>  
>  #define _SMBPROFILE_COUNT_INCREMENT(_stats, _area, _v) do { \
> -	if (do_profile_flag) { \
> -		(_area)->_stats.count += (_v); \
> +	if (smbprofile_state.config.do_count) { \
> +		(_area)->values._stats.count += (_v); \
> +		smbprofile_dump_schedule(); \
>  	} \
>  } while(0)
>  #define SMBPROFILE_COUNT_INCREMENT(_name, _area, _v) \
> @@ -361,7 +367,7 @@ struct profile_stats {
>  #define _SMBPROFILE_TIME_ASYNC_START(_stats, _area, _async) do { \
>  	(_async) = (struct smbprofile_stats_time_async) {}; \
>  	if (smbprofile_state.config.do_times) { \
> -		(_async).stats = &((_area)->_stats), \
> +		(_async).stats = &((_area)->values._stats), \
>  		(_async).start = profile_timestamp(); \
>  	} \
>  } while(0)
> @@ -371,6 +377,7 @@ struct profile_stats {
>  	if ((_async).start != 0) { \
>  		(_async).stats->time += profile_timestamp() - (_async).start; \
>  		(_async) = (struct smbprofile_stats_basic_async) {}; \
> +		smbprofile_dump_schedule(); \
>  	} \
>  } while(0)
>  
> @@ -378,12 +385,13 @@ struct profile_stats {
>  	struct smbprofile_stats_basic_async _async_name;
>  #define _SMBPROFILE_BASIC_ASYNC_START(_stats, _area, _async) do { \
>  	(_async) = (struct smbprofile_stats_basic_async) {}; \
> -	if (do_profile_flag) { \
> -		if (do_profile_times) { \
> +	if (smbprofile_state.config.do_count) { \
> +		if (smbprofile_state.config.do_times) { \
>  			(_async).start = profile_timestamp(); \
> -			(_async).stats = &((_area)->_stats); \
> +			(_async).stats = &((_area)->values._stats); \
>  		} \
> -		(_area)->_stats.count += 1; \
> +		(_area)->values._stats.count += 1; \
> +		smbprofile_dump_schedule(); \
>  	} \
>  } while(0)
>  #define SMBPROFILE_BASIC_ASYNC_START(_name, _area, _async) \
> @@ -392,12 +400,13 @@ struct profile_stats {
>  	if ((_async).start != 0) { \
>  		(_async).stats->time += profile_timestamp() - (_async).start; \
>  		(_async) = (struct smbprofile_stats_basic_async) {}; \
> +		smbprofile_dump_schedule(); \
>  	} \
>  } while(0)
>  
>  #define _SMBPROFILE_TIMER_ASYNC_START(_stats, _area, _async) do { \
> -	(_async).stats = &((_area)->_stats); \
> -	if (do_profile_times) { \
> +	(_async).stats = &((_area)->values._stats); \
> +	if (smbprofile_state.config.do_times) { \
>  		(_async).start = profile_timestamp(); \
>  	} \
>  } while(0)
> @@ -427,10 +436,11 @@ struct profile_stats {
>  	struct smbprofile_stats_bytes_async _async_name;
>  #define _SMBPROFILE_BYTES_ASYNC_START(_stats, _area, _async, _bytes) do { \
>  	(_async) = (struct smbprofile_stats_bytes_async) {}; \
> -	if (do_profile_flag) { \
> +	if (smbprofile_state.config.do_count) { \
>  		_SMBPROFILE_TIMER_ASYNC_START(_stats, _area, _async); \
> -		(_area)->_stats.count += 1; \
> -		(_area)->_stats.bytes += (_bytes); \
> +		(_area)->values._stats.count += 1; \
> +		(_area)->values._stats.bytes += (_bytes); \
> +		smbprofile_dump_schedule(); \
>  	} \
>  } while(0)
>  #define SMBPROFILE_BYTES_ASYNC_START(_name, _area, _async, _bytes) \
> @@ -443,6 +453,7 @@ struct profile_stats {
>  	if ((_async).stats != NULL) { \
>  		_SMBPROFILE_TIMER_ASYNC_END(_async); \
>  		(_async) = (struct smbprofile_stats_bytes_async) {}; \
> +		smbprofile_dump_schedule(); \
>  	} \
>  } while(0)
>  
> @@ -450,10 +461,11 @@ struct profile_stats {
>  	struct smbprofile_stats_iobytes_async _async_name;
>  #define _SMBPROFILE_IOBYTES_ASYNC_START(_stats, _area, _async, _inbytes) do { \
>  	(_async) = (struct smbprofile_stats_iobytes_async) {}; \
> -	if (do_profile_flag) { \
> +	if (smbprofile_state.config.do_count) { \
>  		_SMBPROFILE_TIMER_ASYNC_START(_stats, _area, _async); \
> -		(_area)->_stats.count += 1; \
> -		(_area)->_stats.inbytes += (_inbytes); \
> +		(_area)->values._stats.count += 1; \
> +		(_area)->values._stats.inbytes += (_inbytes); \
> +		smbprofile_dump_schedule(); \
>  	} \
>  } while(0)
>  #define SMBPROFILE_IOBYTES_ASYNC_START(_name, _area, _async, _inbytes) \
> @@ -467,12 +479,62 @@ struct profile_stats {
>  		(_async).stats->outbytes += (_outbytes); \
>  		_SMBPROFILE_TIMER_ASYNC_END(_async); \
>  		(_async) = (struct smbprofile_stats_iobytes_async) {}; \
> +		smbprofile_dump_schedule(); \
>  	} \
>  } while(0)
>  
>  extern struct profile_stats *profile_p;
> -extern bool do_profile_flag;
> -extern bool do_profile_times;
> +
> +struct smbprofile_global_state {
> +	struct {
> +		struct tdb_wrap *db;
> +		struct tevent_context *ev;
> +		struct tevent_timer *te;
> +	} internal;
> +
> +	struct {
> +		bool do_count;
> +		bool do_times;
> +	} config;
> +
> +	struct {
> +		struct profile_stats global;
> +	} stats;
> +};
> +
> +extern struct smbprofile_global_state smbprofile_state;
> +
> +void smbprofile_dump_schedule_timer(void);
> +void smbprofile_dump_setup(struct tevent_context *ev);
> +
> +static inline void smbprofile_dump_schedule(void)
> +{
> +	if (likely(smbprofile_state.internal.te != NULL)) {
> +		return;
> +	}
> +
> +	if (unlikely(smbprofile_state.internal.ev == NULL)) {
> +		return;
> +	}
> +
> +	smbprofile_dump_schedule_timer();
> +}
> +
> +static inline bool smbprofile_dump_pending(void)
> +{
> +	if (smbprofile_state.internal.te == NULL) {
> +		return false;
> +	}
> +
> +	return true;
> +}
> +
> +void smbprofile_dump(void);
> +
> +void smbprofile_cleanup(pid_t pid);
> +void smbprofile_stats_accumulate(struct profile_stats *acc,
> +				 const struct profile_stats *add);
> +void smbprofile_collect(struct profile_stats *stats);
>  
>  static inline uint64_t profile_timestamp(void)
>  {
> @@ -531,6 +593,26 @@ static inline uint64_t profile_timestamp(void)
>  #define END_PROFILE(x)
>  #define END_PROFILE_BYTES(x)
>  
> +static inline bool smbprofile_dump_pending(void)
> +{
> +	return false;
> +}
> +
> +static inline void smbprofile_dump_setup(struct tevent_context *ev)
> +{
> +	return;
> +}
> +
> +static inline void smbprofile_dump(void)
> +{
> +	return;
> +}
> +
> +static inline void smbprofile_cleanup(pid_t pid)
> +{
> +	return;
> +}
> +
>  #endif /* WITH_PROFILE */
>  
>  /* The following definitions come from profile/profile.c  */
> diff --git a/source3/profile/profile.c b/source3/profile/profile.c
> index c720638..7002537 100644
> --- a/source3/profile/profile.c
> +++ b/source3/profile/profile.c
> @@ -24,54 +24,42 @@
>  #include "system/filesys.h"
>  #include "messages.h"
>  #include "smbprofile.h"
> +#include "lib/tdb_wrap/tdb_wrap.h"
> +#include <tevent.h>
> +#include "../lib/crypto/crypto.h"
>  
> -#define PROF_SHMEM_KEY ((key_t)0x07021999)
> -#define PROF_SHM_MAGIC 0x6349985
> -#define PROF_SHM_VERSION 15
> -
> -#define IPC_PERMS ((S_IRUSR | S_IWUSR) | S_IRGRP | S_IROTH)
> -
> -static int shm_id;
> -static bool read_only;
> -
> -struct profile_header {
> -	int prof_shm_magic;
> -	int prof_shm_version;
> -	struct profile_stats stats;
> -};
> -
> -static struct profile_header *profile_h;
>  struct profile_stats *profile_p;
> -
> -bool do_profile_flag = False;
> -bool do_profile_times = False;
> +struct smbprofile_global_state smbprofile_state;
>  
>  /****************************************************************************
>  Set a profiling level.
>  ****************************************************************************/
>  void set_profile_level(int level, struct server_id src)
>  {
> +	SMB_ASSERT(smbprofile_state.internal.db != NULL);
> +
>  	switch (level) {
>  	case 0:		/* turn off profiling */
> -		do_profile_flag = False;
> -		do_profile_times = False;
> +		smbprofile_state.config.do_count = false;
> +		smbprofile_state.config.do_times = false;
>  		DEBUG(1,("INFO: Profiling turned OFF from pid %d\n",
>  			 (int)procid_to_pid(&src)));
>  		break;
>  	case 1:		/* turn on counter profiling only */
> -		do_profile_flag = True;
> -		do_profile_times = False;
> +		smbprofile_state.config.do_count = true;
> +		smbprofile_state.config.do_times = false;
>  		DEBUG(1,("INFO: Profiling counts turned ON from pid %d\n",
>  			 (int)procid_to_pid(&src)));
>  		break;
>  	case 2:		/* turn on complete profiling */
> -		do_profile_flag = True;
> -		do_profile_times = True;
> +		smbprofile_state.config.do_count = true;
> +		smbprofile_state.config.do_times = true;
>  		DEBUG(1,("INFO: Full profiling turned ON from pid %d\n",
>  			 (int)procid_to_pid(&src)));
>  		break;
>  	case 3:		/* reset profile values */
> -		memset((char *)profile_p, 0, sizeof(*profile_p));
> +		ZERO_STRUCT(profile_p->values);
> +		tdb_wipe_all(smbprofile_state.internal.db->tdb);
>  		DEBUG(1,("INFO: Profiling values cleared from pid %d\n",
>  			 (int)procid_to_pid(&src)));
>  		break;
> @@ -109,7 +97,13 @@ static void reqprofile_message(struct messaging_context *msg_ctx,
>  {
>          int level;
>  
> -	level = 1 + (do_profile_flag?2:0) + (do_profile_times?4:0);
> +	level = 1;
> +	if (smbprofile_state.config.do_count) {
> +		level += 2;
> +	}
> +	if (smbprofile_state.config.do_times) {
> +		level += 4;
> +	}
>  
>  	DEBUG(1,("INFO: Received REQ_PROFILELEVEL message from PID %u\n",
>  		 (unsigned int)procid_to_pid(&src)));
> @@ -122,75 +116,302 @@ static void reqprofile_message(struct messaging_context *msg_ctx,
>    ******************************************************************/
>  bool profile_setup(struct messaging_context *msg_ctx, bool rdonly)
>  {
> -	struct shmid_ds shm_ds;
> +	unsigned char tmp[16] = {};
> +	MD5_CTX md5;
> +	char *db_name;
>  
> -	read_only = rdonly;
> +	if (smbprofile_state.internal.db != NULL) {
> +		return true;
> +	}
>  
> - again:
> -	/* try to use an existing key */
> -	shm_id = shmget(PROF_SHMEM_KEY, 0, 0);
> +	db_name = cache_path("smbprofile.tdb");
> +	if (db_name == NULL) {
> +		return false;
> +	}
>  
> -	/* if that failed then create one. There is a race condition here
> -	   if we are running from inetd. Bad luck. */
> -	if (shm_id == -1) {
> -		if (read_only) return False;
> -		shm_id = shmget(PROF_SHMEM_KEY, sizeof(*profile_h),
> -				IPC_CREAT | IPC_EXCL | IPC_PERMS);
> +	smbprofile_state.internal.db = tdb_wrap_open(
> +		NULL, db_name, 0,
> +		rdonly ? 0 : TDB_CLEAR_IF_FIRST|TDB_MUTEX_LOCKING,
> +		O_CREAT | (rdonly ? O_RDONLY : O_RDWR), 0644);
> +	if (smbprofile_state.internal.db == NULL) {
> +		return false;
>  	}
>  
> -	if (shm_id == -1) {
> -		DEBUG(0,("Can't create or use IPC area. Error was %s\n",
> -			 strerror(errno)));
> -		return False;
> +	if (msg_ctx != NULL) {
> +		messaging_register(msg_ctx, NULL, MSG_PROFILE,
> +				   profile_message);
> +		messaging_register(msg_ctx, NULL, MSG_REQ_PROFILELEVEL,
> +				   reqprofile_message);
>  	}
>  
> -	profile_h = (struct profile_header *)shmat(shm_id, 0,
> -						   read_only?SHM_RDONLY:0);
> -	if ((long)profile_h == -1) {
> -		DEBUG(0,("Can't attach to IPC area. Error was %s\n",
> -			 strerror(errno)));
> -		return False;
> +	MD5Init(&md5);
> +
> +	MD5Update(&md5,
> +		  (const uint8_t *)&smbprofile_state.stats.global,
> +		  sizeof(smbprofile_state.stats.global));
> +
> +#define __UPDATE(str) do { \
> +	MD5Update(&md5, (const uint8_t *)str, strlen(str)); \
> +} while(0)
> +#define SMBPROFILE_STATS_START
> +#define SMBPROFILE_STATS_SECTION_START(name, display) do { \
> +	__UPDATE(#name "+" #display); \
> +} while(0);
> +#define SMBPROFILE_STATS_COUNT(name) do { \
> +	__UPDATE(#name "+count"); \
> +} while(0);
> +#define SMBPROFILE_STATS_TIME(name) do { \
> +	__UPDATE(#name "+time"); \
> +} while(0);
> +#define SMBPROFILE_STATS_BASIC(name) do { \
> +	__UPDATE(#name "+count"); \
> +	__UPDATE(#name "+time"); \
> +} while(0);
> +#define SMBPROFILE_STATS_BYTES(name) do { \
> +	__UPDATE(#name "+count"); \
> +	__UPDATE(#name "+time"); \
> +	__UPDATE(#name "+idle"); \
> +	__UPDATE(#name "+bytes"); \
> +} while(0);
> +#define SMBPROFILE_STATS_IOBYTES(name) do { \
> +	__UPDATE(#name "+count"); \
> +	__UPDATE(#name "+time"); \
> +	__UPDATE(#name "+idle"); \
> +	__UPDATE(#name "+inbytes"); \
> +	__UPDATE(#name "+outbytes"); \
> +} while(0);
> +#define SMBPROFILE_STATS_SECTION_END
> +#define SMBPROFILE_STATS_END
> +	SMBPROFILE_STATS_ALL_SECTIONS
> +#undef __UPDATE
> +#undef SMBPROFILE_STATS_START
> +#undef SMBPROFILE_STATS_SECTION_START
> +#undef SMBPROFILE_STATS_COUNT
> +#undef SMBPROFILE_STATS_TIME
> +#undef SMBPROFILE_STATS_BASIC
> +#undef SMBPROFILE_STATS_BYTES
> +#undef SMBPROFILE_STATS_IOBYTES
> +#undef SMBPROFILE_STATS_SECTION_END
> +#undef SMBPROFILE_STATS_END
> +
> +	MD5Final(tmp, &md5);
> +
> +	profile_p = &smbprofile_state.stats.global;
> +
> +	profile_p->magic = BVAL(tmp, 0);
> +	if (profile_p->magic == 0) {
> +		profile_p->magic = BVAL(tmp, 8);
>  	}
>  
> -	/* find out who created this memory area */
> -	if (shmctl(shm_id, IPC_STAT, &shm_ds) != 0) {
> -		DEBUG(0,("ERROR shmctl : can't IPC_STAT. Error was %s\n",
> -			 strerror(errno)));
> -		return False;
> +	return True;
> +}
> +
> +void smbprofile_dump_setup(struct tevent_context *ev)
> +{
> +	TALLOC_FREE(smbprofile_state.internal.te);
> +	smbprofile_state.internal.ev = ev;
> +}
> +
> +static void smbprofile_dump_timer(struct tevent_context *ev,
> +				  struct tevent_timer *te,
> +				  struct timeval current_time,
> +				  void *private_data)
> +{
> +	smbprofile_dump();
> +}
> +
> +void smbprofile_dump_schedule_timer(void)
> +{
> +	struct timeval tv;
> +
> +	GetTimeOfDay(&tv);
> +	tv.tv_sec += 1;
> +
> +	smbprofile_state.internal.te = tevent_add_timer(
> +				smbprofile_state.internal.ev,
> +				smbprofile_state.internal.ev,
> +				tv,
> +				smbprofile_dump_timer,
> +				NULL);
> +}
> +
> +static int profile_stats_parser(TDB_DATA key, TDB_DATA value,
> +				void *private_data)
> +{
> +	struct profile_stats *s = private_data;
> +
> +	if (value.dsize != sizeof(struct profile_stats)) {
> +		*s = (struct profile_stats) {};
> +		return 0;
>  	}
>  
> -	if (shm_ds.shm_perm.cuid != sec_initial_uid() ||
> -	    shm_ds.shm_perm.cgid != sec_initial_gid()) {
> -		DEBUG(0,("ERROR: we did not create the shmem "
> -			 "(owned by another user, uid %u, gid %u)\n",
> -			 shm_ds.shm_perm.cuid,
> -			 shm_ds.shm_perm.cgid));
> -		return False;
> +	memcpy(s, value.dptr, value.dsize);
> +	if (s->magic != profile_p->magic) {
> +		*s = (struct profile_stats) {};
> +		return 0;
>  	}
>  
> -	if (shm_ds.shm_segsz != sizeof(*profile_h)) {
> -		DEBUG(0,("WARNING: profile size is %d (expected %d). Deleting\n",
> -			 (int)shm_ds.shm_segsz, (int)sizeof(*profile_h)));
> -		if (shmctl(shm_id, IPC_RMID, &shm_ds) == 0) {
> -			goto again;
> -		} else {
> -			return False;
> -		}
> +	return 0;
> +}
> +
> +void smbprofile_dump(void)
> +{
> +	pid_t pid = getpid();
> +	TDB_DATA key = { .dptr = (uint8_t *)&pid, .dsize = sizeof(pid) };
> +	struct profile_stats s = {};
> +	int ret;
> +
> +	TALLOC_FREE(smbprofile_state.internal.te);
> +
> +	if (smbprofile_state.internal.db == NULL) {
> +		return;
>  	}
>  
> -	if (!read_only && (shm_ds.shm_nattch == 1)) {
> -		memset((char *)profile_h, 0, sizeof(*profile_h));
> -		profile_h->prof_shm_magic = PROF_SHM_MAGIC;
> -		profile_h->prof_shm_version = PROF_SHM_VERSION;
> -		DEBUG(3,("Initialised profile area\n"));
> +	ret = tdb_chainlock(smbprofile_state.internal.db->tdb, key);
> +	if (ret != 0) {
> +		return;
>  	}
>  
> -	profile_p = &profile_h->stats;
> -	if (msg_ctx != NULL) {
> -		messaging_register(msg_ctx, NULL, MSG_PROFILE,
> -				   profile_message);
> -		messaging_register(msg_ctx, NULL, MSG_REQ_PROFILELEVEL,
> -				   reqprofile_message);
> +	tdb_parse_record(smbprofile_state.internal.db->tdb,
> +			 key, profile_stats_parser, &s);
> +
> +	smbprofile_stats_accumulate(profile_p, &s);
> +
> +	tdb_store(smbprofile_state.internal.db->tdb, key,
> +		  (TDB_DATA) {
> +			.dptr = (uint8_t *)profile_p,
> +			.dsize = sizeof(*profile_p)
> +		  },
> +		  0);
> +
> +	tdb_chainunlock(smbprofile_state.internal.db->tdb, key);
> +	ZERO_STRUCT(profile_p->values);
> +
> +	return;
> +}
> +
> +void smbprofile_cleanup(pid_t pid)
> +{
> +	TDB_DATA key = { .dptr = (uint8_t *)&pid, .dsize = sizeof(pid) };
> +	struct profile_stats s = {};
> +	struct profile_stats acc = {};
> +	int ret;
> +
> +	if (smbprofile_state.internal.db == NULL) {
> +		return;
>  	}
> -	return True;
> +
> +	ret = tdb_chainlock(smbprofile_state.internal.db->tdb, key);
> +	if (ret != 0) {
> +		return;
> +	}
> +	ret = tdb_parse_record(smbprofile_state.internal.db->tdb,
> +			       key, profile_stats_parser, &s);
> +	if (ret == -1) {
> +		tdb_chainunlock(smbprofile_state.internal.db->tdb, key);
> +		return;
> +	}
> +	tdb_delete(smbprofile_state.internal.db->tdb, key);
> +	tdb_chainunlock(smbprofile_state.internal.db->tdb, key);
> +
> +	pid = getpid();
> +	ret = tdb_chainlock(smbprofile_state.internal.db->tdb, key);
> +	if (ret != 0) {
> +		return;
> +	}
> +	tdb_parse_record(smbprofile_state.internal.db->tdb,
> +			 key, profile_stats_parser, &acc);
> +
> +	/*
> +	 * We may have to fix the disconnect count
> +	 * in case the process died
> +	 */
> +	s.values.disconnect_stats.count = s.values.connect_stats.count;
> +
> +	smbprofile_stats_accumulate(&acc, &s);
> +
> +	acc.magic = profile_p->magic;
> +	tdb_store(smbprofile_state.internal.db->tdb, key,
> +		  (TDB_DATA) {
> +			.dptr = (uint8_t *)&acc,
> +			.dsize = sizeof(acc)
> +		  },
> +		  0);
> +
> +	tdb_chainunlock(smbprofile_state.internal.db->tdb, key);
> +}
> +
> +void smbprofile_stats_accumulate(struct profile_stats *acc,
> +				 const struct profile_stats *add)
> +{
> +#define SMBPROFILE_STATS_START
> +#define SMBPROFILE_STATS_SECTION_START(name, display)
> +#define SMBPROFILE_STATS_COUNT(name) do { \
> +	acc->values.name##_stats.count += add->values.name##_stats.count; \
> +} while(0);
> +#define SMBPROFILE_STATS_TIME(name) do { \
> +	acc->values.name##_stats.time += add->values.name##_stats.time; \
> +} while(0);
> +#define SMBPROFILE_STATS_BASIC(name) do { \
> +	acc->values.name##_stats.count += add->values.name##_stats.count; \
> +	acc->values.name##_stats.time += add->values.name##_stats.time; \
> +} while(0);
> +#define SMBPROFILE_STATS_BYTES(name) do { \
> +	acc->values.name##_stats.count += add->values.name##_stats.count; \
> +	acc->values.name##_stats.time += add->values.name##_stats.time; \
> +	acc->values.name##_stats.idle += add->values.name##_stats.idle; \
> +	acc->values.name##_stats.bytes += add->values.name##_stats.bytes; \
> +} while(0);
> +#define SMBPROFILE_STATS_IOBYTES(name) do { \
> +	acc->values.name##_stats.count += add->values.name##_stats.count; \
> +	acc->values.name##_stats.time += add->values.name##_stats.time; \
> +	acc->values.name##_stats.idle += add->values.name##_stats.idle; \
> +	acc->values.name##_stats.inbytes += add->values.name##_stats.inbytes; \
> +	acc->values.name##_stats.outbytes += add->values.name##_stats.outbytes; \
> +} while(0);
> +#define SMBPROFILE_STATS_SECTION_END
> +#define SMBPROFILE_STATS_END
> +	SMBPROFILE_STATS_ALL_SECTIONS
> +#undef SMBPROFILE_STATS_START
> +#undef SMBPROFILE_STATS_SECTION_START
> +#undef SMBPROFILE_STATS_COUNT
> +#undef SMBPROFILE_STATS_TIME
> +#undef SMBPROFILE_STATS_BASIC
> +#undef SMBPROFILE_STATS_BYTES
> +#undef SMBPROFILE_STATS_IOBYTES
> +#undef SMBPROFILE_STATS_SECTION_END
> +#undef SMBPROFILE_STATS_END
> +}
> +
> +static int smbprofile_collect_fn(struct tdb_context *tdb,
> +				 TDB_DATA key, TDB_DATA value,
> +				 void *private_data)
> +{
> +	struct profile_stats *acc = (struct profile_stats *)private_data;
> +	const struct profile_stats *v;
> +
> +	if (value.dsize != sizeof(struct profile_stats)) {
> +		return 0;
> +	}
> +
> +	v = (const struct profile_stats *)value.dptr;
> +
> +	if (v->magic != profile_p->magic) {
> +		return 0;
> +	}
> +
> +	smbprofile_stats_accumulate(acc, v);
> +	return 0;
> +}
> +
> +void smbprofile_collect(struct profile_stats *stats)
> +{
> +	*stats = (struct profile_stats) {};
> +
> +	if (smbprofile_state.internal.db == NULL) {
> +		return;
> +	}
> +
> +	tdb_traverse_read(smbprofile_state.internal.db->tdb,
> +			  smbprofile_collect_fn, stats);
>  }
> diff --git a/source3/smbd/process.c b/source3/smbd/process.c
> index a761669..38edb02 100644
> --- a/source3/smbd/process.c
> +++ b/source3/smbd/process.c
> @@ -3500,6 +3500,7 @@ NTSTATUS smbXsrv_connection_init_tables(struct smbXsrv_connection *conn,
>  }
>  
>  struct smbd_tevent_trace_state {
> +	struct tevent_context *ev;
>  	TALLOC_CTX *frame;
>  	SMBPROFILE_BASIC_ASYNC_STATE(profile_idle);
>  };
> @@ -3512,10 +3513,31 @@ static void smbd_tevent_trace_callback(enum tevent_trace_point point,
>  
>  	switch (point) {
>  	case TEVENT_TRACE_BEFORE_WAIT:
> +		if (!smbprofile_dump_pending()) {
> +			/*
> +			 * If there's no dump pending
> +			 * we don't want to schedule a new 1 sec timer.
> +			 *
> +			 * Instead we want to sleep as long as nothing happens.
> +			 */
> +			smbprofile_dump_setup(NULL);
> +		}
>  		SMBPROFILE_BASIC_ASYNC_START(idle, profile_p, state->profile_idle);
>  		break;
>  	case TEVENT_TRACE_AFTER_WAIT:
>  		SMBPROFILE_BASIC_ASYNC_END(state->profile_idle);
> +		if (!smbprofile_dump_pending()) {
> +			/*
> +			 * We need to flush our state after sleeping
> +			 * (hopefully a long time).
> +			 */
> +			smbprofile_dump();
> +			/*
> +			 * future profiling events should trigger timers
> +			 * on our main event context.
> +			 */
> +			smbprofile_dump_setup(state->ev);
> +		}
>  		break;
>  	case TEVENT_TRACE_BEFORE_LOOP_ONCE:
>  		TALLOC_FREE(state->frame);
> @@ -3766,6 +3788,7 @@ void smbd_process(struct tevent_context *ev_ctx,
>  		  bool interactive)
>  {
>  	struct smbd_tevent_trace_state trace_state = {
> +		.ev = ev_ctx,
>  		.frame = talloc_stackframe(),
>  	};
>  	struct smbXsrv_client *client = NULL;
> @@ -3978,6 +4001,8 @@ void smbd_process(struct tevent_context *ev_ctx,
>  		exit(1);
>  	}
>  
> +	smbprofile_dump_setup(ev_ctx);
> +
>  	if (!init_dptrs(sconn)) {
>  		exit_server("init_dptrs() failed");
>  	}
> diff --git a/source3/smbd/server.c b/source3/smbd/server.c
> index 8207bf1..257c13a 100644
> --- a/source3/smbd/server.c
> +++ b/source3/smbd/server.c
> @@ -428,6 +428,8 @@ static void remove_child_pid(struct smbd_parent_context *parent,
>  			   __func__, strerror(ret)));
>  	}
>  
> +	smbprofile_cleanup(pid);
> +
>  	for (child = parent->children; child != NULL; child = child->next) {
>  		if (child->pid == pid) {
>  			struct smbd_child_pid *tmp = child;
> diff --git a/source3/smbd/server_exit.c b/source3/smbd/server_exit.c
> index e5d32b8..69d0fdd 100644
> --- a/source3/smbd/server_exit.c
> +++ b/source3/smbd/server_exit.c
> @@ -45,6 +45,7 @@
>  #include "serverid.h"
>  #include "messages.h"
>  #include "../lib/util/pidfile.h"
> +#include "smbprofile.h"
>  
>  static struct files_struct *log_writeable_file_fn(
>  	struct files_struct *fsp, void *private_data)
> @@ -232,6 +233,7 @@ static void exit_server_common(enum server_exit_reason how,
>  	xconn = NULL;
>  	client = NULL;
>  	TALLOC_FREE(global_smbXsrv_client);
> +	smbprofile_dump();
>  	server_messaging_context_free();
>  	server_event_context_free();
>  	TALLOC_FREE(smbd_memcache_ctx);
> diff --git a/source3/smbd/smb2_server.c b/source3/smbd/smb2_server.c
> index 432b866..d174fe6 100644
> --- a/source3/smbd/smb2_server.c
> +++ b/source3/smbd/smb2_server.c
> @@ -3090,8 +3090,8 @@ void smbd_smb2_first_negprot(struct smbXsrv_connection *xconn,
>  	 * this was already counted at the SMB1 layer =>
>  	 * smbd_smb2_request_dispatch() should not count it twice.
>  	 */
> -	if (profile_p->request_stats.count > 0) {
> -		profile_p->request_stats.count--;
> +	if (profile_p->values.request_stats.count > 0) {
> +		profile_p->values.request_stats.count--;
>  	}
>  #endif
>  	status = smbd_smb2_request_dispatch(req);
> diff --git a/source3/utils/status_profile.c b/source3/utils/status_profile.c
> index 79c5197..c140456 100644
> --- a/source3/utils/status_profile.c
> +++ b/source3/utils/status_profile.c
> @@ -43,15 +43,19 @@ static void profile_separator(const char * title)
>    ******************************************************************/
>  bool status_profile_dump(bool verbose)
>  {
> +	struct profile_stats stats = {};
> +
>  	if (!profile_setup(NULL, True)) {
>  		fprintf(stderr,"Failed to initialise profile memory\n");
>  		return False;
>  	}
>  
> +	smbprofile_collect(&stats);
> +
>  #define __PRINT_FIELD_LINE(name, _stats, field) do { \
>  	d_printf("%-59s%20ju\n", \
>  		 name "_" #field ":", \
> -		 (uintmax_t)profile_p->_stats.field); \
> +		 (uintmax_t)stats.values._stats.field); \
>  } while(0);
>  #define SMBPROFILE_STATS_START
>  #define SMBPROFILE_STATS_SECTION_START(name, display) profile_separator(#display);
> @@ -248,8 +252,8 @@ static uint64_t print_count_samples(
>  #define SMBPROFILE_STATS_COUNT(name) do { \
>  	count += print_count_count_samples(buf, sizeof(buf), \
>  					   #name, \
> -					   &current->name##_stats, \
> -					   &last->name##_stats, \
> +					   &current->values.name##_stats, \
> +					   &last->values.name##_stats, \
>  					   delta_usec); \
>  } while(0);
>  #define SMBPROFILE_STATS_TIME(name) do { \
> @@ -257,22 +261,22 @@ static uint64_t print_count_samples(
>  #define SMBPROFILE_STATS_BASIC(name) do { \
>  	count += print_basic_count_samples(buf, sizeof(buf), \
>  					   #name, \
> -					   &current->name##_stats, \
> -					   &last->name##_stats, \
> +					   &current->values.name##_stats, \
> +					   &last->values.name##_stats, \
>  					   delta_usec); \
>  } while(0);
>  #define SMBPROFILE_STATS_BYTES(name) do { \
>  	count += print_bytes_count_samples(buf, sizeof(buf), \
>  					   #name, \
> -					   &current->name##_stats, \
> -					   &last->name##_stats, \
> +					   &current->values.name##_stats, \
> +					   &last->values.name##_stats, \
>  					   delta_usec); \
>  } while(0);
>  #define SMBPROFILE_STATS_IOBYTES(name) do { \
>  	count += print_iobytes_count_samples(buf, sizeof(buf), \
>  					     #name, \
> -					     &current->name##_stats, \
> -					     &last->name##_stats, \
> +					     &current->values.name##_stats, \
> +					     &last->values.name##_stats, \
>  					     delta_usec); \
>  } while(0);
>  #define SMBPROFILE_STATS_SECTION_END
> @@ -319,13 +323,13 @@ bool status_profile_rates(bool verbose)
>  		return False;
>  	}
>  
> -	memcpy(&sample_data[last], profile_p, sizeof(*profile_p));
> +	smbprofile_collect(&sample_data[last]);
>  	for (;;) {
>  		sample_time[current] = profile_timestamp();
>  		next_usec = sample_time[current] + sample_interval_usec;
>  
>  		/* Take a sample. */
> -		memcpy(&sample_data[current], profile_p, sizeof(*profile_p));
> +		smbprofile_collect(&sample_data[current]);
>  
>  		/* Rate convert some values and print results. */
>  		delta_usec = sample_time[current] - sample_time[last];
> @@ -383,6 +387,26 @@ struct status_profile_prompt_state {
>  		bool field_inbytes;
>  		bool field_outbytes;
>  	} output;
> +
> +	struct status_profile_prompt_cache {
> +		uint64_t expire_time;
> +		/*
> +		 * In future we may have more than
> +		 * the 'accumulated' values.
> +		 *
> +		 * By having a the prev_cache, we can
> +		 * find out the previous 'needed' state,
> +		 * this way we could predict which values
> +		 * should be calculated by the next
> +		 * cache reload (tdb_traverse_read()).
> +		 */
> +		bool accumulated_needed;
> +		bool accumulated_loaded;
> +	} current_cache, prev_cache;
> +
> +	struct {
> +		struct profile_stats stats;
> +	} accumulated;
>  };
>  
>  static int status_profile_prompt_options(struct status_profile_prompt_state *state)
> @@ -456,8 +480,42 @@ static int status_profile_prompt_options(struct status_profile_prompt_state *sta
>  	return 0;
>  }
>  
> +static int status_profile_reload_cache(struct status_profile_prompt_state *state)
> +{
> +	uint64_t current_time = profile_timestamp();
> +
> +	if (!state->current_cache.accumulated_loaded &&
> +	    state->current_cache.accumulated_needed)
> +	{
> +		state->current_cache.expire_time = 0;
> +	}
> +
> +	if (state->current_cache.expire_time > current_time) {
> +		return 0;
> +	}
> +
> +	state->prev_cache = state->current_cache;
> +
> +	/*
> +	 * The new cache is valid for 1 second
> +	 */
> +	state->current_cache = (struct status_profile_prompt_cache) {
> +		.expire_time = current_time + (1 * 1000 * 1000),
> +	};
> +
> +	if (state->prev_cache.accumulated_needed) {
> +		smbprofile_collect(&state->accumulated.stats);
> +		state->current_cache.accumulated_loaded = true;
> +	}
> +
> +	return 0;
> +}
> +
>  static int status_profile_accumulated(struct status_profile_prompt_state *state)
>  {
> +	state->current_cache.accumulated_needed = true;
> +	status_profile_reload_cache(state);
> +
>  	if (strcmp(state->output.format, "oneline-function") == 0) {
>  #define SMBPROFILE_STATS_START \
>  	d_printf("_response_ begin accumulated\n");
> @@ -482,7 +540,7 @@ static int status_profile_accumulated(struct status_profile_prompt_state *state)
>  	if (state->output.field_##__f) { \
>  		d_printf(" _%s_ %ju", \
>  			 #__f, \
> -			 (uintmax_t)(profile_p->__s.__f)); \
> +			 (uintmax_t)(state->accumulated.stats.values.__s.__f)); \
>  	}
>  #define SMBPROFILE_STATS_COUNT(name) do { \
>  	if (state->output.field_count) { \
> @@ -584,7 +642,7 @@ static int status_profile_accumulated(struct status_profile_prompt_state *state)
>  	if (state->output.field_##__f) { \
>  		d_printf(" _%s_%s_ %ju", \
>  			 __n, #__f, \
> -			 (uintmax_t)(profile_p->__s.__f)); \
> +			 (uintmax_t)(state->accumulated.stats.values.__s.__f)); \
>  	}
>  #define SMBPROFILE_STATS_COUNT(name) do { \
>  	__PREPARE_FIELD_NAME(#name) \
> -- 
> 1.9.1
> 
> 
> From a0b0e35331310bdc87cd82fbc86e5ecfb24a6eeb Mon Sep 17 00:00:00 2001
> From: Stefan Metzmacher <metze at samba.org>
> Date: Mon, 8 Dec 2014 10:30:56 +0100
> Subject: [PATCH 4/7] script/autobuild.py: build the samba target with
>  --with-profiling-data
> 
> In future we may get also runtime tests for profiling...
> 
> Signed-off-by: Stefan Metzmacher <metze at samba.org>
> Reviewed-by: Michael Adam <obnox at samba.org>
> 
> Autobuild-User(master): Michael Adam <obnox at samba.org>
> Autobuild-Date(master): Mon Dec 15 16:20:14 CET 2014 on sn-devel-104
> 
> (cherry picked from commit 4958fcdfa30fd9d8dc51ceafaab35721e61e72c7)
> ---
>  script/autobuild.py | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/script/autobuild.py b/script/autobuild.py
> index 55e4449..6fcdcd4 100755
> --- a/script/autobuild.py
> +++ b/script/autobuild.py
> @@ -44,7 +44,7 @@ tasks = {
>                 ("clean", "make clean", "text/plain") ],
>  
>      # We have 'test' before 'install' because, 'test' should work without 'install'
> -    "samba" : [ ("configure", "./configure.developer --picky-developer ${PREFIX} --with-selftest-prefix=./bin/ab", "text/plain"),
> +    "samba" : [ ("configure", "./configure.developer --picky-developer ${PREFIX} --with-selftest-prefix=./bin/ab  --with-profiling-data", "text/plain"),
>                  ("make", "make -j", "text/plain"),
>                  ("test", "make test FAIL_IMMEDIATELY=1", "text/plain"),
>                  ("install", "make install", "text/plain"),
> -- 
> 1.9.1
> 
> 
> From 1e3e1de2908e9e7b4044b0874bff681355fe2941 Mon Sep 17 00:00:00 2001
> From: Stefan Metzmacher <metze at samba.org>
> Date: Thu, 23 Oct 2014 18:33:06 +0200
> Subject: [PATCH 5/7] selftest: smbd profiling level = on
> 
> Now that we use a tdb for the profiling data instead of sysv shared mem,
> enable profiling in selftest.
> 
> Signed-off-by: Stefan Metzmacher <metze at samba.org>
> Reviewed-by: Ralph Boehme <slow at samba.org>
> ---
>  selftest/target/Samba3.pm | 2 ++
>  1 file changed, 2 insertions(+)
> 
> diff --git a/selftest/target/Samba3.pm b/selftest/target/Samba3.pm
> index 934153c..18f5fc3 100755
> --- a/selftest/target/Samba3.pm
> +++ b/selftest/target/Samba3.pm
> @@ -206,6 +206,8 @@ sub setup_s3dc($$)
>  	domain logons = yes
>  	lanman auth = yes
>  
> +	smbd profiling level = on
> +
>  	rpc_server:epmapper = external
>  	rpc_server:spoolss = external
>  	rpc_server:lsarpc = external
> -- 
> 1.9.1
> 
> 
> From 1de4d52289fb7f4cf091288e4611a723ff5bcac0 Mon Sep 17 00:00:00 2001
> From: Stefan Metzmacher <metze at samba.org>
> Date: Fri, 14 Nov 2014 12:52:33 +0100
> Subject: [PATCH 6/7] s3:smbprofile: profile the system and user space cpu time
> 
> Signed-off-by: Stefan Metzmacher <metze at samba.org>
> Reviewed-by: Ralph Boehme <slow at samba.org>
> ---
>  source3/include/smbprofile.h |  2 ++
>  source3/profile/profile.c    | 22 ++++++++++++++++++++++
>  source3/wscript              |  1 +
>  3 files changed, 25 insertions(+)
> 
> diff --git a/source3/include/smbprofile.h b/source3/include/smbprofile.h
> index b32d938..76d9d2b 100644
> --- a/source3/include/smbprofile.h
> +++ b/source3/include/smbprofile.h
> @@ -32,6 +32,8 @@ struct tevent_context;
>  	SMBPROFILE_STATS_COUNT(connect) \
>  	SMBPROFILE_STATS_COUNT(disconnect) \
>  	SMBPROFILE_STATS_BASIC(idle) \
> +	SMBPROFILE_STATS_TIME(cpu_user) \
> +	SMBPROFILE_STATS_TIME(cpu_system) \
>  	SMBPROFILE_STATS_COUNT(request) \
>  	SMBPROFILE_STATS_BASIC(push_sec_ctx) \
>  	SMBPROFILE_STATS_BASIC(set_sec_ctx) \
> diff --git a/source3/profile/profile.c b/source3/profile/profile.c
> index 7002537..67b1fc7 100644
> --- a/source3/profile/profile.c
> +++ b/source3/profile/profile.c
> @@ -22,12 +22,17 @@
>  #include "includes.h"
>  #include "system/shmem.h"
>  #include "system/filesys.h"
> +#include "system/time.h"
>  #include "messages.h"
>  #include "smbprofile.h"
>  #include "lib/tdb_wrap/tdb_wrap.h"
>  #include <tevent.h>
>  #include "../lib/crypto/crypto.h"
>  
> +#ifdef HAVE_SYS_RESOURCE_H
> +#include <sys/resource.h>
> +#endif
> +
>  struct profile_stats *profile_p;
>  struct smbprofile_global_state smbprofile_state;
>  
> @@ -260,6 +265,9 @@ void smbprofile_dump(void)
>  	TDB_DATA key = { .dptr = (uint8_t *)&pid, .dsize = sizeof(pid) };
>  	struct profile_stats s = {};
>  	int ret;
> +#ifdef HAVE_GETRUSAGE
> +	struct rusage rself;
> +#endif /* HAVE_GETRUSAGE */
>  
>  	TALLOC_FREE(smbprofile_state.internal.te);
>  
> @@ -267,6 +275,20 @@ void smbprofile_dump(void)
>  		return;
>  	}
>  
> +#ifdef HAVE_GETRUSAGE
> +	ret = getrusage(RUSAGE_SELF, &rself);
> +	if (ret != 0) {
> +		ZERO_STRUCT(rself);
> +	}
> +
> +	profile_p->values.cpu_user_stats.time =
> +		(rself.ru_utime.tv_sec * 1000000) +
> +		rself.ru_utime.tv_usec;
> +	profile_p->values.cpu_system_stats.time =
> +		(rself.ru_stime.tv_sec * 1000000) +
> +		rself.ru_stime.tv_usec;
> +#endif /* HAVE_GETRUSAGE */
> +
>  	ret = tdb_chainlock(smbprofile_state.internal.db->tdb, key);
>  	if (ret != 0) {
>  		return;
> diff --git a/source3/wscript b/source3/wscript
> index bb0f19d..d529c19 100644
> --- a/source3/wscript
> +++ b/source3/wscript
> @@ -1484,6 +1484,7 @@ main() {
>  
>      if Options.options.with_profiling_data:
>          conf.DEFINE('WITH_PROFILE', 1);
> +        conf.CHECK_FUNCS('getrusage', headers="sys/time.h sys/resource.h")
>  
>      if Options.options.with_pthreadpool:
>          if conf.CONFIG_SET('HAVE_PTHREAD'):
> -- 
> 1.9.1
> 
> 
> From 50b7ed2a4c852fe39049f3e26c6d9c2937e358ef Mon Sep 17 00:00:00 2001
> From: Stefan Metzmacher <metze at samba.org>
> Date: Mon, 15 Dec 2014 16:42:23 +0100
> Subject: [PATCH 7/7] testprogs/blackbox: add test_smbprofile.sh
> 
> This tests a few smbstatus -P --prompt commands.
> 
> Signed-off-by: Stefan Metzmacher <metze at samba.org>
> Reviewed-by: Ralph Boehme <slow at samba.org>
> ---
>  source3/selftest/tests.py             |   4 +
>  testprogs/blackbox/test_smbprofile.sh | 312 ++++++++++++++++++++++++++++++++++
>  2 files changed, 316 insertions(+)
>  create mode 100755 testprogs/blackbox/test_smbprofile.sh
> 
> diff --git a/source3/selftest/tests.py b/source3/selftest/tests.py
> index 0a59903..b862d2e 100755
> --- a/source3/selftest/tests.py
> +++ b/source3/selftest/tests.py
> @@ -27,6 +27,8 @@ smbtorture4_options.extend([
>     '--option=torture:writetimeupdatedelay=500000',
>     ])
>  
> +bbdir = os.path.join(srcdir(), "testprogs/blackbox")
> +
>  def plansmbtorture4testsuite(name, env, options, description=''):
>      if description == '':
>          modname = "samba3.%s" % (name, )
> @@ -459,3 +461,5 @@ for e in endianness_options:
>              plansmbtorture4testsuite(test, "s3dc", options, 'over ncacn_ip_tcp with [%s%s%s] ' % (a, s, e))
>  
>  plansmbtorture4testsuite('rpc.epmapper', 's3dc:local', 'ncalrpc: -U$USERNAME%$PASSWORD', 'over ncalrpc')
> +
> +plantestsuite("samba.blackbox.smbprofile", "s3dc:local", [os.path.join(bbdir, "test_smbprofile.sh")])
> diff --git a/testprogs/blackbox/test_smbprofile.sh b/testprogs/blackbox/test_smbprofile.sh
> new file mode 100755
> index 0000000..1644761
> --- /dev/null
> +++ b/testprogs/blackbox/test_smbprofile.sh
> @@ -0,0 +1,312 @@
> +#!/bin/sh
> +
> +# this runs a simple smbprofile tests
> +
> +if [ $# -lt 0 ]; then
> +cat <<EOF
> +Usage: test_smbprofile.sh
> +EOF
> +exit 1;
> +fi
> +
> +ADDARGS="$*"
> +
> +failed=0
> +
> +smbstatus="$BINDIR/smbstatus"
> +texpect="$BINDIR/texpect"
> +
> +. `dirname $0`/subunit.sh
> +
> +TEXPECT_SCRIPT="${SELFTEST_TMPDIR}/$(basename $0).texpect"
> +cat > ${TEXPECT_SCRIPT} <<EOF
> +send get-accumulated\n
> +expect _response_ begin accumulated
> +expect _section_ begin global
> +expect connect: _count_ 
> +expect disconnect: _count_ 
> +expect idle: _count_ 
> +expect cpu_user: _time_ 
> +expect cpu_system: _time_ 
> +expect request: _count_ 
> +expect push_sec_ctx: _count_ 
> +expect set_sec_ctx: _count_ 
> +expect set_root_sec_ctx: _count_ 
> +expect pop_sec_ctx: _count_ 
> +expect _section_ end
> +expect _section_ begin syscall
> +expect opendir: _count_ 
> +expect fdopendir: _count_ 
> +expect readdir: _count_ 
> +expect seekdir: _count_ 
> +expect telldir: _count_ 
> +expect rewinddir: _count_ 
> +expect mkdir: _count_ 
> +expect rmdir: _count_ 
> +expect closedir: _count_ 
> +expect open: _count_ 
> +expect createfile: _count_ 
> +expect close: _count_ 
> +expect read: _count_ 
> +expect pread: _count_ 
> +expect asys_pread: _count_ 
> +expect write: _count_ 
> +expect pwrite: _count_ 
> +expect asys_pwrite: _count_ 
> +expect lseek: _count_ 
> +expect sendfile: _count_ 
> +expect recvfile: _count_ 
> +expect rename: _count_ 
> +expect rename_at: _count_ 
> +expect fsync: _count_ 
> +expect asys_fsync: _count_ 
> +expect stat: _count_ 
> +expect fstat: _count_ 
> +expect lstat: _count_ 
> +expect get_alloc_size: _count_ 
> +expect unlink: _count_ 
> +expect chmod: _count_ 
> +expect fchmod: _count_ 
> +expect chown: _count_ 
> +expect fchown: _count_ 
> +expect lchown: _count_ 
> +expect chdir: _count_ 
> +expect getwd: _count_ 
> +expect ntimes: _count_ 
> +expect ftruncate: _count_ 
> +expect fallocate: _count_ 
> +expect fcntl_lock: _count_ 
> +expect kernel_flock: _count_ 
> +expect linux_setlease: _count_ 
> +expect fcntl_getlock: _count_ 
> +expect readlink: _count_ 
> +expect symlink: _count_ 
> +expect link: _count_ 
> +expect mknod: _count_ 
> +expect realpath: _count_ 
> +expect get_quota: _count_ 
> +expect set_quota: _count_ 
> +expect get_sd: _count_ 
> +expect set_sd: _count_ 
> +expect brl_lock: _count_ 
> +expect brl_unlock: _count_ 
> +expect brl_cancel: _count_ 
> +expect _section_ end
> +expect _section_ begin acl
> +expect get_nt_acl: _count_ 
> +expect fget_nt_acl: _count_ 
> +expect fset_nt_acl: _count_ 
> +expect chmod_acl: _count_ 
> +expect fchmod_acl: _count_ 
> +expect _section_ end
> +expect _section_ begin statcache
> +expect lookups: _count_ 
> +expect misses: _count_ 
> +expect hits: _count_ 
> +expect _section_ end
> +expect _section_ begin writecache
> +expect allocations: _count_ 
> +expect deallocations: _count_ 
> +expect cached_reads: _count_ 
> +expect total_writes: _count_ 
> +expect init_writes: _count_ 
> +expect abutted_writes: _count_ 
> +expect non_oplock_writes: _count_ 
> +expect direct_writes: _count_ 
> +expect cached_writes: _count_ 
> +expect perfect_writes: _count_ 
> +expect flush_reason_seek: _count_ 
> +expect flush_reason_read: _count_ 
> +expect flush_reason_readraw: _count_ 
> +expect flush_reason_write: _count_ 
> +expect flush_reason_oplock: _count_ 
> +expect flush_reason_close: _count_ 
> +expect flush_reason_sync: _count_ 
> +expect flush_reason_sizechange: _count_ 
> +expect _section_ end
> +expect _section_ begin SMB
> +expect mkdir: _count_ 
> +expect rmdir: _count_ 
> +expect open: _count_ 
> +expect create: _count_ 
> +expect close: _count_ 
> +expect flush: _count_ 
> +expect unlink: _count_ 
> +expect mv: _count_ 
> +expect getatr: _count_ 
> +expect setatr: _count_ 
> +expect read: _count_ 
> +expect write: _count_ 
> +expect lock: _count_ 
> +expect unlock: _count_ 
> +expect ctemp: _count_ 
> +expect mknew: _count_ 
> +expect checkpath: _count_ 
> +expect exit: _count_ 
> +expect lseek: _count_ 
> +expect lockread: _count_ 
> +expect writeunlock: _count_ 
> +expect readbraw: _count_ 
> +expect readBmpx: _count_ 
> +expect readBs: _count_ 
> +expect writebraw: _count_ 
> +expect writeBmpx: _count_ 
> +expect writeBs: _count_ 
> +expect writec: _count_ 
> +expect setattrE: _count_ 
> +expect getattrE: _count_ 
> +expect lockingX: _count_ 
> +expect trans: _count_ 
> +expect transs: _count_ 
> +expect ioctl: _count_ 
> +expect ioctls: _count_ 
> +expect copy: _count_ 
> +expect move: _count_ 
> +expect echo: _count_ 
> +expect writeclose: _count_ 
> +expect openX: _count_ 
> +expect readX: _count_ 
> +expect writeX: _count_ 
> +expect trans2: _count_ 0 _time_ 0
> +expect transs2: _count_ 0 _time_ 0
> +expect findclose: _count_ 
> +expect findnclose: _count_ 
> +expect tcon: _count_ 
> +expect tdis: _count_ 
> +expect negprot: _count_ 
> +expect sesssetupX: _count_ 
> +expect ulogoffX: _count_ 
> +expect tconX: _count_ 
> +expect dskattr: _count_ 
> +expect search: _count_ 
> +expect ffirst: _count_ 
> +expect funique: _count_ 
> +expect fclose: _count_ 
> +expect nttrans: _count_ 
> +expect nttranss: _count_ 
> +expect ntcreateX: _count_ 
> +expect ntcancel: _count_ 
> +expect ntrename: _count_ 
> +expect splopen: _count_ 
> +expect splwr: _count_ 
> +expect splclose: _count_ 
> +expect splretq: _count_ 
> +expect sends: _count_ 
> +expect sendb: _count_ 
> +expect fwdname: _count_ 
> +expect cancelf: _count_ 
> +expect getmac: _count_ 
> +expect sendstrt: _count_ 
> +expect sendend: _count_ 
> +expect sendtxt: _count_ 
> +expect invalid: _count_ 
> +expect _section_ end
> +expect _section_ begin Trans2
> +expect open: _count_ 
> +expect findfirst: _count_ 
> +expect findnext: _count_ 
> +expect qfsinfo: _count_ 
> +expect setfsinfo: _count_ 
> +expect qpathinfo: _count_ 
> +expect setpathinfo: _count_ 
> +expect qfileinfo: _count_ 
> +expect setfileinfo: _count_ 
> +expect fsctl: _count_ 
> +expect ioctl: _count_ 
> +expect findnotifyfirst: _count_ 
> +expect findnotifynext: _count_ 
> +expect mkdir: _count_ 
> +expect session_setup: _count_ 
> +expect get_dfs_referral: _count_ 
> +expect report_dfs_inconsistancy: _count_ 
> +expect _section_ end
> +expect _section_ begin NT_transact
> +expect create: _count_ 
> +expect ioctl: _count_ 
> +expect set_security_desc: _count_ 
> +expect notify_change: _count_ 
> +expect rename: _count_ 
> +expect query_security_desc: _count_ 
> +expect get_user_quota: _count_ 
> +expect set_user_quota: _count_ 
> +expect _section_ end
> +expect _section_ begin smb2
> +expect negprot: _count_ 
> +expect sesssetup: _count_ 
> +expect logoff: _count_ 
> +expect tcon: _count_ 
> +expect tdis: _count_ 
> +expect create: _count_ 
> +expect close: _count_ 
> +expect flush: _count_ 
> +expect read: _count_ 
> +expect write: _count_ 
> +expect lock: _count_ 
> +expect ioctl: _count_ 
> +expect cancel: _count_ 
> +expect keepalive: _count_ 
> +expect find: _count_ 
> +expect notify: _count_ 
> +expect getinfo: _count_ 
> +expect setinfo: _count_ 
> +expect break: _count_ 
> +expect _section_ end
> +expect _response_ end
> +send get-accumulated --format=oneline-function --sections=smb2\n
> +expect _response_ begin accumulated
> +expect _section_ begin smb2
> +expect negprot: _count_ 
> +expect sesssetup: _count_ 
> +expect logoff: _count_ 
> +expect tcon: _count_ 
> +expect tdis: _count_ 
> +expect create: _count_ 
> +expect close: _count_ 
> +expect flush: _count_ 
> +expect read: _count_ 
> +expect write: _count_ 
> +expect lock: _count_ 
> +expect ioctl: _count_ 
> +expect cancel: _count_ 
> +expect keepalive: _count_ 
> +expect find: _count_ 
> +expect notify: _count_ 
> +expect getinfo: _count_ 
> +expect setinfo: _count_ 
> +expect break: _count_ 
> +expect _section_ end
> +expect _response_ end
> +send get-accumulated --format=oneline-section --sections=global\n
> +expect _response_ begin accumulated
> +expect global: _connect_count_ 
> +expect _response_ end
> +send get-accumulated --format=oneline-function --sections=smb2\n
> +expect _response_ begin accumulated
> +expect _section_ begin smb2
> +expect negprot: _count_ 
> +expect sesssetup: _count_ 
> +expect logoff: _count_ 
> +expect tcon: _count_ 
> +expect tdis: _count_ 
> +expect create: _count_ 
> +expect close: _count_ 
> +expect flush: _count_ 
> +expect read: _count_ 
> +expect write: _count_ 
> +expect lock: _count_ 
> +expect ioctl: _count_ 
> +expect cancel: _count_ 
> +expect keepalive: _count_ 
> +expect find: _count_ 
> +expect notify: _count_ 
> +expect getinfo: _count_ 
> +expect setinfo: _count_ 
> +expect break: _count_ 
> +expect _section_ end
> +expect _response_ end
> +send exit\n
> +EOF
> +
> +testit "check smbstatus -P --prompt" $texpect ${TEXPECT_SCRIPT} $VALGRIND $smbstatus -P --prompt || failed=`expr $failed + 1`
> +
> +testok $0 $failed
> -- 
> 1.9.1
> 





More information about the samba-technical mailing list