From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 27862 invoked by alias); 21 Aug 2013 15:08:41 -0000 Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org Received: (qmail 27846 invoked by uid 89); 21 Aug 2013 15:08:40 -0000 X-Spam-SWARE-Status: No, score=-1.0 required=5.0 tests=AWL,BAYES_00,MSGID_MULTIPLE_AT autolearn=no version=3.3.2 Received: from mailhost.u-strasbg.fr (HELO mailhost.u-strasbg.fr) (130.79.201.45) by sourceware.org (qpsmtpd/0.84/v0.84-167-ge50287c) with ESMTP; Wed, 21 Aug 2013 15:08:39 +0000 Received: from md15.u-strasbg.fr (md15.u-strasbg.fr [130.79.200.204]) by mailhost.u-strasbg.fr (8.14.3/jtpda-5.5pre1) with ESMTP id r7LF8YE7020331 for ; Wed, 21 Aug 2013 17:08:34 +0200 (CEST) (envelope-from pierre.muller@ics-cnrs.unistra.fr) Received: from ms14.u-strasbg.fr (ms14.u-strasbg.fr [130.79.204.114]) by md15.u-strasbg.fr (8.14.3/jtpda-5.5pre1) with ESMTP id r7LF8YwL012049 for ; Wed, 21 Aug 2013 17:08:34 +0200 (envelope-from pierre.muller@ics-cnrs.unistra.fr) Received: from E6510Muller (gw-ics.u-strasbg.fr [130.79.210.225]) (Authenticated sender: mullerp) by ms14.u-strasbg.fr (Postfix) with ESMTPSA id 90B281FD84 for ; Wed, 21 Aug 2013 17:08:34 +0200 (CEST) From: "Pierre Muller" To: Subject: [RFC] Add possibility to force buffering mode for stdout/stderr Date: Wed, 21 Aug 2013 15:08:00 -0000 Message-ID: <001201ce9e80$4b90b3e0$e2b21ba0$@muller@ics-cnrs.unistra.fr> MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit X-SW-Source: 2013-08/txt/msg00586.txt.bz2 This patch add setvbuf wrapping inside ui_file structure. This maintenance feature is to allow to test the effect of changing the buffering mode on the testsuite output. basically adding "-ex {maint setvbuf stdout full 1000000}" or "-ex {maint setvbuf stdout line 80}" should allow to test both performance differences induced by buffering changes and possible regressions in testsuite results. This patch is really only of interest to developers using the testsuite or wanting to investigate performance issues related to buffering. I implemented it after the thread about forcing the buffering mode for mingw build GDB executables. The advantage of this patch is that: - there are no changes in the default behavior - any executable can be tested, not only mingw builds like in the other thread. - it should be a tool to understand the change between line buffering and no buffering. The patch itself is probably not perfect yet and comments are most welcome. Pierre Muller 2013-08-21 Pierre Muller Implement new 'maintenance setvbuf' command. * ui-file.h (ui_file_setvbuf_ftype): New function type prototype. (set_ui_file_setvbuf): New function. (ui_file_setvbuf): New function. * ui-file.c (struct ui_file): Add to_setvbuf field. (ui_file_new): Add call to set_ui_file_setvbuf. (null_file_setvbuf): Dummy function for non stdio variants. (ui_file_fseek): (set_ui_file_setvbuf): New function. (struct stdio_file): Add buf field. (stdio_file_new): Initialize buf field and to_setvbuf. (stdio_file_delete): Call xfree on BUF if non NULL. (stdio_file_setvbuf): New function call libc setvbuf function. * maint.c (maintenance_setvbuf): New function. (_initialize_maint_cmds): Register new 'maintenance setvbuf' command. Index: ui-file.h =================================================================== RCS file: /cvs/src/src/gdb/ui-file.h,v retrieving revision 1.22 diff -u -p -r1.22 ui-file.h --- ui-file.h 14 May 2013 20:35:24 -0000 1.22 +++ ui-file.h 21 Aug 2013 14:12:51 -0000 @@ -33,6 +33,11 @@ typedef void (ui_file_flush_ftype) (stru extern void set_ui_file_flush (struct ui_file *stream, ui_file_flush_ftype *flush); +typedef int (ui_file_setvbuf_ftype) (struct ui_file *stream, char *buf, + int mode, size_t size); +extern void set_ui_file_setvbuf (struct ui_file *stream, + ui_file_setvbuf_ftype *setvbuf); + /* NOTE: Both fputs and write methods are available. Default implementations that mapping one onto the other are included. */ typedef void (ui_file_write_ftype) (struct ui_file *stream, @@ -120,6 +125,9 @@ extern long ui_file_read (struct ui_file extern int ui_file_fseek (struct ui_file *file, long offset, int whence); +extern int ui_file_setvbuf (struct ui_file *file, char *buf, + int mode, size_t size); + /* Create/open a memory based file. Can be used as a scratch buffer for collecting output. */ extern struct ui_file *mem_fileopen (void); Index: ui-file.c =================================================================== RCS file: /cvs/src/src/gdb/ui-file.c,v retrieving revision 1.36 diff -u -p -r1.36 ui-file.c --- ui-file.c 14 May 2013 20:35:24 -0000 1.36 +++ ui-file.c 21 Aug 2013 14:12:51 -0000 @@ -38,6 +38,7 @@ static ui_file_delete_ftype null_file_de static ui_file_rewind_ftype null_file_rewind; static ui_file_put_ftype null_file_put; static ui_file_fseek_ftype null_file_fseek; +static ui_file_setvbuf_ftype null_file_setvbuf; struct ui_file { @@ -52,6 +53,7 @@ struct ui_file ui_file_rewind_ftype *to_rewind; ui_file_put_ftype *to_put; ui_file_fseek_ftype *to_fseek; + ui_file_setvbuf_ftype * to_setvbuf; void *to_data; }; int ui_file_magic; @@ -64,6 +66,7 @@ ui_file_new (void) file->magic = &ui_file_magic; set_ui_file_data (file, NULL, null_file_delete); set_ui_file_flush (file, null_file_flush); + set_ui_file_setvbuf (file, null_file_setvbuf); set_ui_file_write (file, null_file_write); set_ui_file_write_async_safe (file, null_file_write_async_safe); set_ui_file_fputs (file, null_file_fputs); @@ -108,6 +111,13 @@ null_file_flush (struct ui_file *file) return; } +static int +null_file_setvbuf (struct ui_file *file, char *buf, int mode, size_t size) +{ + /* Indicates failure as non-zero result. */ + return 1; +} + static void null_file_write (struct ui_file *file, const char *buf, @@ -245,6 +255,12 @@ ui_file_fseek (struct ui_file *file, lon return file->to_fseek (file, offset, whence); } +int +ui_file_setvbuf (struct ui_file *file, char *buf, int mode, int size) +{ + return file->to_setvbuf (file, buf, mode, size); +} + void fputs_unfiltered (const char *buf, struct ui_file *file) { @@ -258,6 +274,12 @@ set_ui_file_flush (struct ui_file *file, } void +set_ui_file_setvbuf (struct ui_file *file, ui_file_setvbuf_ftype *setvbuf_ptr) +{ + file->to_setvbuf = setvbuf_ptr; +} + +void set_ui_file_isatty (struct ui_file *file, ui_file_isatty_ftype *isatty_ptr) { file->to_isatty = isatty_ptr; @@ -493,6 +515,7 @@ static ui_file_isatty_ftype stdio_file_i static ui_file_delete_ftype stdio_file_delete; static struct ui_file *stdio_file_new (FILE *file, int close_p); static ui_file_flush_ftype stdio_file_flush; +static ui_file_setvbuf_ftype stdio_file_setvbuf; static ui_file_fseek_ftype stdio_file_fseek; static int stdio_file_magic; @@ -505,6 +528,9 @@ struct stdio_file stdio_file_write_async_safe's benefit, in case fileno isn't async-safe. */ int fd; int close_p; + /* The buf that might have been assigned using to_setvbuf call. + This buffer should be allocated using xmalloc. */ + char *buf; }; static struct ui_file * @@ -517,8 +543,10 @@ stdio_file_new (FILE *file, int close_p) stdio->file = file; stdio->fd = fileno (file); stdio->close_p = close_p; + stdio->buf = NULL; set_ui_file_data (ui_file, stdio, stdio_file_delete); set_ui_file_flush (ui_file, stdio_file_flush); + set_ui_file_setvbuf (ui_file, stdio_file_setvbuf); set_ui_file_write (ui_file, stdio_file_write); set_ui_file_write_async_safe (ui_file, stdio_file_write_async_safe); set_ui_file_fputs (ui_file, stdio_file_fputs); @@ -540,6 +568,8 @@ stdio_file_delete (struct ui_file *file) { fclose (stdio->file); } + if (stdio->buf) + xfree (stdio->buf); xfree (stdio); } @@ -554,6 +584,25 @@ stdio_file_flush (struct ui_file *file) fflush (stdio->file); } +static int +stdio_file_setvbuf (struct ui_file *file, char *buf, int mode, size_t size) +{ + int res; + struct stdio_file *stdio = ui_file_data (file); + + if (stdio->magic != &stdio_file_magic) + internal_error (__FILE__, __LINE__, + _("stdio_file_setvbuf: bad magic number")); + res = setvbuf (stdio->file, buf, mode, size); + if (res == 0) + { + if (stdio->buf) + xfree (stdio->buf); + stdio->buf = buf; + } + return res; +} + static long stdio_file_read (struct ui_file *file, char *buf, long length_buf) { @@ -577,6 +626,22 @@ stdio_file_read (struct ui_file *file, c return read (stdio->fd, buf, length_buf); } +/* Force flush if same file descriptor as gdb_stderr. */ + +static void +stdio_maybe_flush (struct ui_file *file) +{ + if (gdb_stderr && (gdb_stderr->magic == &ui_file_magic)) + { + struct stdio_file *stderr_stdio = ui_file_data (gdb_stderr); + struct stdio_file *stdio = ui_file_data (file); + + if (stderr_stdio->magic == &stdio_file_magic + && stderr_stdio->fd == stdio->fd) + file->to_flush (file); + } +} + static void stdio_file_write (struct ui_file *file, const char *buf, long length_buf) { @@ -590,6 +655,7 @@ stdio_file_write (struct ui_file *file, { /* Nothing. */ } + stdio_maybe_flush (file); } static void @@ -614,6 +680,7 @@ stdio_file_write_async_safe (struct ui_f { /* Nothing. */ } + stdio_maybe_flush (file); } static void @@ -629,6 +696,7 @@ stdio_file_fputs (const char *linebuffer { /* Nothing. */ } + stdio_maybe_flush (file); } static int Index: maint.c =================================================================== RCS file: /cvs/src/src/gdb/maint.c,v retrieving revision 1.95 diff -u -p -r1.95 maint.c --- maint.c 8 Apr 2013 20:20:46 -0000 1.95 +++ maint.c 21 Aug 2013 14:12:52 -0000 @@ -55,6 +55,8 @@ static void maintenance_internal_error ( static void maintenance_demangle (char *, int); +static void maintenance_setvbuf (char *, int); + static void maintenance_time_display (char *, int); static void maintenance_space_display (char *, int); @@ -165,6 +167,88 @@ maintenance_demangle (char *args, int fr } } +/* Force standard files to specific bbufferingg mode. */ +static void +maintenance_setvbuf (char *args, int from_tty) +{ + char *file; + char *mode; + char *size; + + if (args == NULL || *args == '\0') + { + printf_unfiltered (_("\"maintenance setvbuf\" takes " + "\"stdout/stderr\" and \"full/line/no\"" + " optionally followed by buffer size.\n")); + } + else + { + struct ui_file *f = NULL; + if (strncmp (args, "stdout ", strlen ("stdout ")) == 0) + { + f = gdb_stdout; + args += strlen ("stdout "); + } + else if (strncmp (args, "stderr ", strlen ("stderr ")) == 0) + { + f = gdb_stderr; + args += strlen ("stderr "); + } + + if (f == NULL) + { + printf_unfiltered (_("\"maintenance setvbuf\" accepts only " + "\"stdout\" or \"stderr\" as first argument.\n")); + } + else + { + int mode = -1; + + if (strncmp (args, "full", strlen ("full")) == 0) + { + mode = _IOFBF; + args += strlen ("full"); + } + else if (strncmp (args, "line", strlen ("line")) == 0) + { + mode = _IOLBF; + args += strlen ("line"); + } + else if (strncmp (args, "no", strlen ("no")) == 0) + { + mode = _IONBF; + args += strlen ("no"); + } + if (mode == -1) + { + printf_unfiltered (_("\"maintenance setvbuf\" accepts only " + "\"full\",\"line\" or \"no\" as second" + " argument.\n")); + } + else + { + char *buf = NULL; + ULONGEST size; + int res; + + if (args && *args != '\0') + size = parse_and_eval_long (args); + else + size = BUFSIZ; + if (mode != _IONBF) + buf = (char *) xmalloc (size); + res = ui_file_setvbuf (f, buf, mode, size); + if (res != 0) + { + if (buf) + xfree (buf); + printf_unfiltered (_("Call to setvbuf failed.\n")); + } + } + } + } +} + static void maintenance_time_display (char *args, int from_tty) { @@ -1123,6 +1207,9 @@ Takes an optional file parameter."), _("Translate a section name and address to a symbol."), &maintenancelist); + add_cmd ("setvbuf", class_maintenance, maintenance_setvbuf, + _("Force stdout/stderr buffering mode."), &maintenancelist); + add_cmd ("deprecate", class_maintenance, maintenance_deprecate, _("\ Deprecate a command. Note that this is just in here so the \n\ testsuite can check the command deprecator. You probably shouldn't use this,\n\z to GDBFLAGS in site.exp for testsuite runs Pierre Muller GDB pascal language maintainer 2013-08-21 Pierre Muller Implement new 'maintenance setvbuf' command. * ui-file.h (ui_file_setvbuf_ftype): New function type prototype. (set_ui_file_setvbuf): New function. (ui_file_setvbuf): New function. * ui-file.c (struct ui_file): Add to_setvbuf field. (ui_file_new): Add call to set_ui_file_setvbuf. (null_file_setvbuf): Dummy function for non stdio variants. (ui_file_fseek): (set_ui_file_setvbuf): New function. (struct stdio_file): Add buf field. (stdio_file_new): Initialize buf field and to_setvbuf. (stdio_file_delete): Call xfree on BUF if non NULL. (stdio_file_setvbuf): New function call libc setvbuf function. * maint.c (maintenance_setvbuf): New function. (_initialize_maint_cmds): Register new 'maintenance setvbuf' command. Index: ui-file.h =================================================================== RCS file: /cvs/src/src/gdb/ui-file.h,v retrieving revision 1.22 diff -u -p -r1.22 ui-file.h --- ui-file.h 14 May 2013 20:35:24 -0000 1.22 +++ ui-file.h 21 Aug 2013 14:12:51 -0000 @@ -33,6 +33,11 @@ typedef void (ui_file_flush_ftype) (stru extern void set_ui_file_flush (struct ui_file *stream, ui_file_flush_ftype *flush); +typedef int (ui_file_setvbuf_ftype) (struct ui_file *stream, char *buf, + int mode, size_t size); +extern void set_ui_file_setvbuf (struct ui_file *stream, + ui_file_setvbuf_ftype *setvbuf); + /* NOTE: Both fputs and write methods are available. Default implementations that mapping one onto the other are included. */ typedef void (ui_file_write_ftype) (struct ui_file *stream, @@ -120,6 +125,9 @@ extern long ui_file_read (struct ui_file extern int ui_file_fseek (struct ui_file *file, long offset, int whence); +extern int ui_file_setvbuf (struct ui_file *file, char *buf, + int mode, size_t size); + /* Create/open a memory based file. Can be used as a scratch buffer for collecting output. */ extern struct ui_file *mem_fileopen (void); Index: ui-file.c =================================================================== RCS file: /cvs/src/src/gdb/ui-file.c,v retrieving revision 1.36 diff -u -p -r1.36 ui-file.c --- ui-file.c 14 May 2013 20:35:24 -0000 1.36 +++ ui-file.c 21 Aug 2013 14:12:51 -0000 @@ -38,6 +38,7 @@ static ui_file_delete_ftype null_file_de static ui_file_rewind_ftype null_file_rewind; static ui_file_put_ftype null_file_put; static ui_file_fseek_ftype null_file_fseek; +static ui_file_setvbuf_ftype null_file_setvbuf; struct ui_file { @@ -52,6 +53,7 @@ struct ui_file ui_file_rewind_ftype *to_rewind; ui_file_put_ftype *to_put; ui_file_fseek_ftype *to_fseek; + ui_file_setvbuf_ftype * to_setvbuf; void *to_data; }; int ui_file_magic; @@ -64,6 +66,7 @@ ui_file_new (void) file->magic = &ui_file_magic; set_ui_file_data (file, NULL, null_file_delete); set_ui_file_flush (file, null_file_flush); + set_ui_file_setvbuf (file, null_file_setvbuf); set_ui_file_write (file, null_file_write); set_ui_file_write_async_safe (file, null_file_write_async_safe); set_ui_file_fputs (file, null_file_fputs); @@ -108,6 +111,13 @@ null_file_flush (struct ui_file *file) return; } +static int +null_file_setvbuf (struct ui_file *file, char *buf, int mode, size_t size) +{ + /* Indicates failure as non-zero result. */ + return 1; +} + static void null_file_write (struct ui_file *file, const char *buf, @@ -245,6 +255,12 @@ ui_file_fseek (struct ui_file *file, lon return file->to_fseek (file, offset, whence); } +int +ui_file_setvbuf (struct ui_file *file, char *buf, int mode, int size) +{ + return file->to_setvbuf (file, buf, mode, size); +} + void fputs_unfiltered (const char *buf, struct ui_file *file) { @@ -258,6 +274,12 @@ set_ui_file_flush (struct ui_file *file, } void +set_ui_file_setvbuf (struct ui_file *file, ui_file_setvbuf_ftype *setvbuf_ptr) +{ + file->to_setvbuf = setvbuf_ptr; +} + +void set_ui_file_isatty (struct ui_file *file, ui_file_isatty_ftype *isatty_ptr) { file->to_isatty = isatty_ptr; @@ -493,6 +515,7 @@ static ui_file_isatty_ftype stdio_file_i static ui_file_delete_ftype stdio_file_delete; static struct ui_file *stdio_file_new (FILE *file, int close_p); static ui_file_flush_ftype stdio_file_flush; +static ui_file_setvbuf_ftype stdio_file_setvbuf; static ui_file_fseek_ftype stdio_file_fseek; static int stdio_file_magic; @@ -505,6 +528,9 @@ struct stdio_file stdio_file_write_async_safe's benefit, in case fileno isn't async-safe. */ int fd; int close_p; + /* The buf that might have been assigned using to_setvbuf call. + This buffer should be allocated using xmalloc. */ + char *buf; }; static struct ui_file * @@ -517,8 +543,10 @@ stdio_file_new (FILE *file, int close_p) stdio->file = file; stdio->fd = fileno (file); stdio->close_p = close_p; + stdio->buf = NULL; set_ui_file_data (ui_file, stdio, stdio_file_delete); set_ui_file_flush (ui_file, stdio_file_flush); + set_ui_file_setvbuf (ui_file, stdio_file_setvbuf); set_ui_file_write (ui_file, stdio_file_write); set_ui_file_write_async_safe (ui_file, stdio_file_write_async_safe); set_ui_file_fputs (ui_file, stdio_file_fputs); @@ -540,6 +568,8 @@ stdio_file_delete (struct ui_file *file) { fclose (stdio->file); } + if (stdio->buf) + xfree (stdio->buf); xfree (stdio); } @@ -554,6 +584,25 @@ stdio_file_flush (struct ui_file *file) fflush (stdio->file); } +static int +stdio_file_setvbuf (struct ui_file *file, char *buf, int mode, size_t size) +{ + int res; + struct stdio_file *stdio = ui_file_data (file); + + if (stdio->magic != &stdio_file_magic) + internal_error (__FILE__, __LINE__, + _("stdio_file_setvbuf: bad magic number")); + res = setvbuf (stdio->file, buf, mode, size); + if (res == 0) + { + if (stdio->buf) + xfree (stdio->buf); + stdio->buf = buf; + } + return res; +} + static long stdio_file_read (struct ui_file *file, char *buf, long length_buf) { @@ -577,6 +626,22 @@ stdio_file_read (struct ui_file *file, c return read (stdio->fd, buf, length_buf); } +/* Force flush if same file descriptor as gdb_stderr. */ + +static void +stdio_maybe_flush (struct ui_file *file) +{ + if (gdb_stderr && (gdb_stderr->magic == &ui_file_magic)) + { + struct stdio_file *stderr_stdio = ui_file_data (gdb_stderr); + struct stdio_file *stdio = ui_file_data (file); + + if (stderr_stdio->magic == &stdio_file_magic + && stderr_stdio->fd == stdio->fd) + file->to_flush (file); + } +} + static void stdio_file_write (struct ui_file *file, const char *buf, long length_buf) { @@ -590,6 +655,7 @@ stdio_file_write (struct ui_file *file, { /* Nothing. */ } + stdio_maybe_flush (file); } static void @@ -614,6 +680,7 @@ stdio_file_write_async_safe (struct ui_f { /* Nothing. */ } + stdio_maybe_flush (file); } static void @@ -629,6 +696,7 @@ stdio_file_fputs (const char *linebuffer { /* Nothing. */ } + stdio_maybe_flush (file); } static int Index: maint.c =================================================================== RCS file: /cvs/src/src/gdb/maint.c,v retrieving revision 1.95 diff -u -p -r1.95 maint.c --- maint.c 8 Apr 2013 20:20:46 -0000 1.95 +++ maint.c 21 Aug 2013 14:12:52 -0000 @@ -55,6 +55,8 @@ static void maintenance_internal_error ( static void maintenance_demangle (char *, int); +static void maintenance_setvbuf (char *, int); + static void maintenance_time_display (char *, int); static void maintenance_space_display (char *, int); @@ -165,6 +167,88 @@ maintenance_demangle (char *args, int fr } } +/* Force standard files to specific bbufferingg mode. */ +static void +maintenance_setvbuf (char *args, int from_tty) +{ + char *file; + char *mode; + char *size; + + if (args == NULL || *args == '\0') + { + printf_unfiltered (_("\"maintenance setvbuf\" takes " + "\"stdout/stderr\" and \"full/line/no\"" + " optionally followed by buffer size.\n")); + } + else + { + struct ui_file *f = NULL; + if (strncmp (args, "stdout ", strlen ("stdout ")) == 0) + { + f = gdb_stdout; + args += strlen ("stdout "); + } + else if (strncmp (args, "stderr ", strlen ("stderr ")) == 0) + { + f = gdb_stderr; + args += strlen ("stderr "); + } + + if (f == NULL) + { + printf_unfiltered (_("\"maintenance setvbuf\" accepts only " + "\"stdout\" or \"stderr\" as first argument.\n")); + } + else + { + int mode = -1; + + if (strncmp (args, "full", strlen ("full")) == 0) + { + mode = _IOFBF; + args += strlen ("full"); + } + else if (strncmp (args, "line", strlen ("line")) == 0) + { + mode = _IOLBF; + args += strlen ("line"); + } + else if (strncmp (args, "no", strlen ("no")) == 0) + { + mode = _IONBF; + args += strlen ("no"); + } + if (mode == -1) + { + printf_unfiltered (_("\"maintenance setvbuf\" accepts only " + "\"full\",\"line\" or \"no\" as second" + " argument.\n")); + } + else + { + char *buf = NULL; + ULONGEST size; + int res; + + if (args && *args != '\0') + size = parse_and_eval_long (args); + else + size = BUFSIZ; + if (mode != _IONBF) + buf = (char *) xmalloc (size); + res = ui_file_setvbuf (f, buf, mode, size); + if (res != 0) + { + if (buf) + xfree (buf); + printf_unfiltered (_("Call to setvbuf failed.\n")); + } + } + } + } +} + static void maintenance_time_display (char *args, int from_tty) { @@ -1123,6 +1207,9 @@ Takes an optional file parameter."), _("Translate a section name and address to a symbol."), &maintenancelist); + add_cmd ("setvbuf", class_maintenance, maintenance_setvbuf, + _("Force stdout/stderr buffering mode."), &maintenancelist); + add_cmd ("deprecate", class_maintenance, maintenance_deprecate, _("\ Deprecate a command. Note that this is just in here so the \n\ testsuite can check the command deprecator. You probably shouldn't use this,\n\