Why our autobuilds fail

Stefan (metze) Metzmacher metze at samba.org
Mon Mar 2 09:29:25 MST 2015


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.

metze
-------------- next part --------------
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

-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 181 bytes
Desc: OpenPGP digital signature
URL: <http://lists.samba.org/pipermail/samba-technical/attachments/20150302/c3b75fb9/attachment.pgp>


More information about the samba-technical mailing list