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, \
> - ¤t->name##_stats, \
> - &last->name##_stats, \
> + ¤t->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, \
> - ¤t->name##_stats, \
> - &last->name##_stats, \
> + ¤t->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, \
> - ¤t->name##_stats, \
> - &last->name##_stats, \
> + ¤t->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, \
> - ¤t->name##_stats, \
> - &last->name##_stats, \
> + ¤t->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