unofficial mirror of bug-gnu-emacs@gnu.org 
 help / color / mirror / code / Atom feed
* bug#10580: 24.0.92; gdb initialization takes more than one minute at 100% CPU
@ 2012-01-22 12:42 Dov Grobgeld
  2012-01-23  0:53 ` Glenn Morris
  2012-12-14  4:14 ` bug#10580: 24.0.92; gdb initialization takes more than one minute at 100 Jean-Philippe Gravel
  0 siblings, 2 replies; 48+ messages in thread
From: Dov Grobgeld @ 2012-01-22 12:42 UTC (permalink / raw)
  To: 10580

This bug report will be sent to the Bug-GNU-Emacs mailing list
and the GNU bug tracker at debbugs.gnu.org.  Please check that
the From: line contains a valid email address.  After a delay of up
to one day, you should receive an acknowledgement at that address.

Please write in English if possible, as the Emacs maintainers
usually do not have translators for other languages.

Please describe exactly what actions triggered the bug, and
the precise symptoms of the bug.  If you can, give a recipe
starting from `emacs -Q':

------------------------------

When trying to running gdb on my process, emacs gets stuck for more than
one minutes while the CPU load is at 100%.

Running gdb from the shell buffer yields the following response:

> gdb -i=mi SolarJet
=thread-group-added,id="i1"
~"GNU gdb (GDB) Fedora (7.2-52.fc14)\n"
~"Copyright (C) 2010 Free Software Foundation, Inc.\n"
~"License GPLv3+: GNU GPL version 3 or later
<http://gnu.org/licenses/gpl.html>\nThis is free software: you are
free to change and redistribute it.\nThere is NO WARRANTY, to the
extent permitted by law.  Type \"show copying\"\nand \"show warranty\"
for details.\n"
~"This GDB was configured as \"i686-redhat-linux-gnu\".\nFor bug
reporting instructions, please see:\n"
~"<http://www.gnu.org/software/gdb/bugs/>...\n"
~"Reading symbols from
/mnt/fdrive/git/SolarJet/Apps/SolarJet/Project/qt/BinLinux32/SolarJet..."
~"done.\n"
(gdb)

But as I said, running it by Meta-x gdb SolarJet yields the following
message, and then emacs gets stuck for more than one minute:

Reading symbols from
/mnt/fdrive/git/SolarJet/Apps/SolarJet/Project/qt/BinLinux32/SolarJet...done.

Note that in earlier versions of emacs (23.2.1), the gdb prompt was
received immediately after the done message has been shown.

---------------------------------


If Emacs crashed, and you have the Emacs process in the gdb debugger,
please include the output from the following gdb commands:
    `bt full' and `xbacktrace'.
For information about debugging Emacs, please read the file
/usr/local/public-dev/share/emacs/24.0.92/etc/DEBUG.


In GNU Emacs 24.0.92.1 (i686-pc-linux-gnu, GTK+ Version 2.22.0)
 of 2012-01-22 on dovg32
Windowing system distributor `Fedora Project', version 11.0.10905000
configured using `configure  '--prefix=/usr/local/public-dev''

Important settings:
  value of $LC_ALL: nil
  value of $LC_COLLATE: nil
  value of $LC_CTYPE: nil
  value of $LC_MESSAGES: nil
  value of $LC_MONETARY: nil
  value of $LC_NUMERIC: nil
  value of $LC_TIME: nil
  value of $LANG: en_US.utf8
  value of $XMODIFIERS: nil
  locale-coding-system: utf-8-unix
  default enable-multibyte-characters: t

Major mode: Dired by name

Minor modes in effect:
  show-paren-mode: t
  shell-dirtrack-mode: t
  csv-field-index-mode: t
  xmsi-mode: t
  diff-auto-refine-mode: t
  delete-selection-mode: t
  tooltip-mode: t
  mouse-wheel-mode: t
  menu-bar-mode: t
  file-name-shadow-mode: t
  global-font-lock-mode: t
  font-lock-mode: t
  auto-composition-mode: t
  auto-encryption-mode: t
  auto-compression-mode: t
  column-number-mode: t
  line-number-mode: t
  transient-mark-mode: t

Recent input:

Recent messages:
No previous history command
The program is not being run.
Quit [2 times]
Mark set
Error during redisplay: (void-variable font-lock-shell-prompt-face)
/mnt/fdrive/git/SolarJet/Apps/SolarJet/Project/qt
Error during redisplay: (void-variable font-lock-shell-prompt-face) [2 times]
Error during redisplay: (void-variable font-lock-shell-cmd-args-face) [14 times]
Error during redisplay: (void-variable font-lock-shell-prompt-face)
gud-query-cmdline: Command attempted to use minibuffer while in minibuffer

Load-path shadows:
/home/dov/.config/emacs/longlines hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/longlines
/home/dov/.config/emacs/cedet/common/ezimage hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/ezimage
/home/dov/.config/emacs/cedet/speedbar/sb-image hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/sb-image
/home/dov/.config/emacs/cedet/speedbar/dframe hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/dframe
/home/dov/.config/emacs/cedet/speedbar/speedbar hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/speedbar
/home/dov/.config/emacs/octave-inf hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/progmodes/octave-inf
/home/dov/.config/emacs/gdb-mi hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/progmodes/gdb-mi
/home/dov/.config/emacs/octave-mod hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/progmodes/octave-mod
/home/dov/.config/emacs/compile hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/progmodes/compile
/home/dov/.config/emacs/org-mode/ob-org hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/ob-org
/home/dov/.config/emacs/org-mode/org-attach hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/org-attach
/home/dov/.config/emacs/org-mode/ob-lilypond hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/ob-lilypond
/home/dov/.config/emacs/org-mode/org-remember hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/org-remember
/home/dov/.config/emacs/org-mode/org-bbdb hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/org-bbdb
/home/dov/.config/emacs/org-mode/org-mhe hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/org-mhe
/home/dov/.config/emacs/org-mode/org-src hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/org-src
/home/dov/.config/emacs/org-mode/org-wl hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/org-wl
/home/dov/.config/emacs/org-mode/ob-table hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/ob-table
/home/dov/.config/emacs/org-mode/ob-comint hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/ob-comint
/home/dov/.config/emacs/org-mode/ob-mscgen hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/ob-mscgen
/home/dov/.config/emacs/org-mode/org-ascii hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/org-ascii
/home/dov/.config/emacs/org-mode/org-freemind hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/org-freemind
/home/dov/.config/emacs/org-mode/org-w3m hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/org-w3m
/home/dov/.config/emacs/org-mode/org-compat hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/org-compat
/home/dov/.config/emacs/org-mode/ob-screen hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/ob-screen
/home/dov/.config/emacs/org-mode/ob-matlab hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/ob-matlab
/home/dov/.config/emacs/org-mode/ob-keys hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/ob-keys
/home/dov/.config/emacs/org-mode/ob-asymptote hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/ob-asymptote
/home/dov/.config/emacs/org-mode/ob-emacs-lisp hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/ob-emacs-lisp
/home/dov/.config/emacs/org-mode/org-archive hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/org-archive
/home/dov/.config/emacs/org-mode/org-docbook hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/org-docbook
/home/dov/.config/emacs/org-mode/org-list hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/org-list
/home/dov/.config/emacs/org-mode/ob-ditaa hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/ob-ditaa
/home/dov/.config/emacs/org-mode/ob-C hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/ob-C
/home/dov/.config/emacs/org-mode/org-exp hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/org-exp
/home/dov/.config/emacs/org-mode/ob-exp hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/ob-exp
/home/dov/.config/emacs/org-mode/ob-ocaml hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/ob-ocaml
/home/dov/.config/emacs/org-mode/org-faces hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/org-faces
/home/dov/.config/emacs/org-mode/org-entities hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/org-entities
/home/dov/.config/emacs/org-mode/ob-perl hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/ob-perl
/home/dov/.config/emacs/org-mode/org-footnote hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/org-footnote
/home/dov/.config/emacs/org-mode/org-info hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/org-info
/home/dov/.config/emacs/org-mode/org-exp-blocks hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/org-exp-blocks
/home/dov/.config/emacs/org-mode/org-inlinetask hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/org-inlinetask
/home/dov/.config/emacs/org-mode/ob-ruby hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/ob-ruby
/home/dov/.config/emacs/org-mode/ob-eval hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/ob-eval
/home/dov/.config/emacs/org-mode/org-colview hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/org-colview
/home/dov/.config/emacs/org-mode/org-agenda hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/org-agenda
/home/dov/.config/emacs/org-mode/org-beamer hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/org-beamer
/home/dov/.config/emacs/org-mode/ob-lisp hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/ob-lisp
/home/dov/.config/emacs/org-mode/org-mks hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/org-mks
/home/dov/.config/emacs/org-mode/ob-latex hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/ob-latex
/home/dov/.config/emacs/org-mode/org-html hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/org-html
/home/dov/.config/emacs/org-mode/org-jsinfo hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/org-jsinfo
/home/dov/.config/emacs/org-mode/ob-sh hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/ob-sh
/home/dov/.config/emacs/org-mode/org-timer hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/org-timer
/home/dov/.config/emacs/org-mode/ob-python hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/ob-python
/home/dov/.config/emacs/org-mode/ob hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/ob
/home/dov/.config/emacs/org-mode/ob-octave hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/ob-octave
/home/dov/.config/emacs/org-mode/org-xoxo hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/org-xoxo
/home/dov/.config/emacs/org-mode/org-crypt hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/org-crypt
/home/dov/.config/emacs/org-mode/ob-scheme hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/ob-scheme
/home/dov/.config/emacs/org-mode/org-plot hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/org-plot
/home/dov/.config/emacs/org-mode/org-icalendar hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/org-icalendar
/home/dov/.config/emacs/org-mode/ob-gnuplot hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/ob-gnuplot
/home/dov/.config/emacs/org-mode/ob-dot hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/ob-dot
/home/dov/.config/emacs/org-mode/org-datetree hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/org-datetree
/home/dov/.config/emacs/org-mode/ob-css hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/ob-css
/home/dov/.config/emacs/org-mode/ob-plantuml hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/ob-plantuml
/home/dov/.config/emacs/org-mode/org-rmail hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/org-rmail
/home/dov/.config/emacs/org-mode/org-habit hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/org-habit
/home/dov/.config/emacs/org-mode/org-mouse hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/org-mouse
/home/dov/.config/emacs/org-mode/org-latex hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/org-latex
/home/dov/.config/emacs/org-mode/org-ctags hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/org-ctags
/home/dov/.config/emacs/org-mode/ob-sqlite hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/ob-sqlite
/home/dov/.config/emacs/org-mode/ob-clojure hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/ob-clojure
/home/dov/.config/emacs/org-mode/org-taskjuggler hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/org-taskjuggler
/home/dov/.config/emacs/org-mode/org-capture hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/org-capture
/home/dov/.config/emacs/org-mode/org-mew hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/org-mew
/home/dov/.config/emacs/org-mode/org-vm hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/org-vm
/home/dov/.config/emacs/org-mode/org-id hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/org-id
/home/dov/.config/emacs/org-mode/org-publish hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/org-publish
/home/dov/.config/emacs/org-mode/org-indent hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/org-indent
/home/dov/.config/emacs/org-mode/ob-sass hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/ob-sass
/home/dov/.config/emacs/org-mode/ob-ref hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/ob-ref
/home/dov/.config/emacs/org-mode/org-macs hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/org-macs
/home/dov/.config/emacs/org-mode/ob-ledger hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/ob-ledger
/home/dov/.config/emacs/org-mode/org-clock hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/org-clock
/home/dov/.config/emacs/org-mode/ob-calc hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/ob-calc
/home/dov/.config/emacs/org-mode/org-special-blocks hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/org-special-blocks
/home/dov/.config/emacs/org-mode/org-mobile hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/org-mobile
/home/dov/.config/emacs/org-mode/ob-java hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/ob-java
/home/dov/.config/emacs/org-mode/org-table hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/org-table
/home/dov/.config/emacs/org-mode/ob-awk hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/ob-awk
/home/dov/.config/emacs/org-mode/ob-lob hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/ob-lob
/home/dov/.config/emacs/org-mode/ob-haskell hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/ob-haskell
/home/dov/.config/emacs/org-mode/org-pcomplete hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/org-pcomplete
/home/dov/.config/emacs/org-mode/ob-maxima hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/ob-maxima
/home/dov/.config/emacs/org-mode/ob-sql hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/ob-sql
/home/dov/.config/emacs/org-mode/ob-js hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/ob-js
/home/dov/.config/emacs/org-mode/org-irc hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/org-irc
/home/dov/.config/emacs/org-mode/ob-R hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/ob-R
/home/dov/.config/emacs/org-mode/org-feed hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/org-feed
/home/dov/.config/emacs/org-mode/org hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/org
/home/dov/.config/emacs/org-mode/ob-tangle hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/ob-tangle
/home/dov/.config/emacs/org-mode/org-docview hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/org-docview
/home/dov/.config/emacs/org-mode/org-gnus hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/org-gnus
/home/dov/.config/emacs/org-mode/org-mac-message hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/org-mac-message
/home/dov/.config/emacs/org-mode/org-bibtex hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/org-bibtex
/home/dov/.config/emacs/org-mode/org-protocol hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/org/org-protocol
/home/dov/.config/emacs/cedet/eieio/eieio-speedbar hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/emacs-lisp/eieio-speedbar
/home/dov/.config/emacs/cedet/eieio/eieio-custom hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/emacs-lisp/eieio-custom
/home/dov/.config/emacs/cedet/eieio/eieio-opt hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/emacs-lisp/eieio-opt
/home/dov/.config/emacs/cedet/eieio/chart hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/emacs-lisp/chart
/home/dov/.config/emacs/cedet/eieio/eieio-base hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/emacs-lisp/eieio-base
/home/dov/.config/emacs/cedet/eieio/eieio hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/emacs-lisp/eieio
/home/dov/.config/emacs/cedet/eieio/eieio-datadebug hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/emacs-lisp/eieio-datadebug
/home/dov/.config/emacs/cedet/common/cedet-files hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/cedet/cedet-files
/home/dov/.config/emacs/cedet/common/inversion hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/cedet/inversion
/home/dov/.config/emacs/cedet/common/data-debug hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/cedet/data-debug
/home/dov/.config/emacs/cedet/ede/ede hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/cedet/ede
/home/dov/.config/emacs/cedet/semantic/semantic hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/cedet/semantic
/home/dov/.config/emacs/cedet/common/cedet-global hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/cedet/cedet-global
/home/dov/.config/emacs/cedet/srecode/srecode hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/cedet/srecode
/home/dov/.config/emacs/cedet/common/pulse hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/cedet/pulse
/home/dov/.config/emacs/cedet/common/cedet-cscope hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/cedet/cedet-cscope
/home/dov/.config/emacs/cedet/common/mode-local hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/cedet/mode-local
/home/dov/.config/emacs/cedet/common/cedet-idutils hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/cedet/cedet-idutils
/home/dov/.config/emacs/cedet/common/cedet hides
/usr/local/public-dev/share/emacs/24.0.92/lisp/cedet/cedet

Features:
(shadow mail-extr emacsbug gdb-mi bindat json vc-git face-remap org-wl
org-w3m org-vm org-rmail org-mhe org-mew org-irc org-jsinfo org-infojs
org-html org-info org-gnus org-docview org-bibtex bibtex org-bbdb paren
zoom-frm qtdoc browse-url cedet ede-speedbar ede-files ede ede-base
data-debug ede-auto eieio-speedbar speedbar ange-ftp sb-image ezimage
dframe eieio-custom ede-source eieio-base mode-local find-func inversion
git-find-file org-mw ob-plantuml ob-asymptote ob-dot ob-ditaa ob-python
ob-perl ob-sh org-htmlslidy org-s5 persistent ipython executable
org-export iimage org-install screenshot dmacro tramp tramp-compat
tramp-loaddefs tex-mode shell color-moccur matlab-load sourcepair
csv-mode sort dired-details+ dired-details mediawiki url-cache mm-url
url-http tls url-auth url-gw python-mode ansi-color tempo url url-proxy
url-privacy url-expand url-methods url-history url-cookie url-util
url-parse auth-source eieio password-cache url-vars mailcap xml-parse
doxymacs ack epresent org-latex org-export-latex org-beamer footnote
org-exp ob-exp org-exp-blocks org-agenda org advice advice-preload
ob-emacs-lisp ob-tangle ob-ref ob-lob ob-table org-footnote org-src
ob-comint ob-keys ob ob-eval org-pcomplete pcomplete org-list org-faces
org-compat org-entities org-macs cal-menu calendar cal-loaddefs nnir
gnus-sum nnoo gnus-group gnus-undo nnmail mail-source gnus-start
gnus-spec gnus-int gnus-range gnus-win gnus gnus-ems nnheader gnus-util
xmsi-math-symbols-input mo-git-blame scroll-all markdown-mode noutline
outline magit-bisect magit-key-mode assoc magit esh-var esh-io esh-cmd
esh-ext esh-proc esh-arg eldoc esh-groups eshell esh-module esh-mode
esh-util help-fns ido iswitchb diff-mode log-edit pcvs-util add-log
vc-ediff octave-mod csharp-mode byte-opt bytecomp byte-compile cconv
macroexp cc-langs doc-mode derived sgml-mode gud message format-spec
rfc822 mml mml-sec mm-decode mm-bodies mm-encode mail-parse rfc2231
rfc2047 rfc2045 ietf-drums mm-util mail-prsvr mailabbrev mail-utils
gmm-utils mailheader delsel warnings server javascript-mode newcomment
icicles icicles-mode icicles-cmd frame-cmds frame-fns avoid dired+
dired-x dired-aux dired cus-edit cus-start cus-load yow cookie1 etags
compile easy-mmode imenu comint ring bookmark pp dabbrev recentf
tree-widget icicles-mcmd help-mode view icicles-mac icicles-fn cl
icicles-face icicles-var icicles-opt ffap wid-edit edmacro kmacro
thingatpt gtk-look info-look info vc ediff-merg ediff-diff ediff-wind
ediff-help ediff-util ediff-mult ediff-init ediff vc-dispatcher cc-mode
cc-fonts easymenu cc-guess cc-menus cc-cmds cc-styles cc-align cc-engine
cc-vars cc-defs regexp-opt time-date tooltip ediff-hook vc-hooks
lisp-float-type mwheel x-win x-dnd tool-bar dnd fontset image fringe
lisp-mode register page menu-bar rfn-eshadow timer select scroll-bar
mouse jit-lock font-lock syntax facemenu font-core frame cham georgian
utf-8-lang misc-lang vietnamese tibetan thai tai-viet lao korean
japanese hebrew greek romanian slovak czech european ethiopic indian
cyrillic chinese case-table epa-hook jka-cmpr-hook help simple abbrev
minibuffer loaddefs button faces cus-face files text-properties overlay
sha1 md5 base64 format env code-pages mule custom widget
hashtable-print-readable backquote make-network-process dynamic-setting
system-font-setting font-render-setting move-toolbar gtk x-toolkit x
multi-tty emacs)





^ permalink raw reply	[flat|nested] 48+ messages in thread

* bug#10580: 24.0.92; gdb initialization takes more than one minute at 100% CPU
  2012-01-22 12:42 bug#10580: 24.0.92; gdb initialization takes more than one minute at 100% CPU Dov Grobgeld
@ 2012-01-23  0:53 ` Glenn Morris
       [not found]   ` <CA++fsGG4YuTtb2VC9R+GRcPN5+JSaKpkb+uO3WAX0+VXmh8HDQ@mail.gmail.com>
  2012-12-14  4:14 ` bug#10580: 24.0.92; gdb initialization takes more than one minute at 100 Jean-Philippe Gravel
  1 sibling, 1 reply; 48+ messages in thread
From: Glenn Morris @ 2012-01-23  0:53 UTC (permalink / raw)
  To: Dov Grobgeld; +Cc: 10580

Dov Grobgeld wrote:

> When trying to running gdb on my process, emacs gets stuck for more than
> one minutes while the CPU load is at 100%.

Does this happen with `emacs -Q'? Because it looks like you may not be
using the gdb that comes with Emacs:

> /home/dov/.config/emacs/gdb-mi hides
> /usr/local/public-dev/share/emacs/24.0.92/lisp/progmodes/gdb-mi





^ permalink raw reply	[flat|nested] 48+ messages in thread

* bug#10580: 24.0.92; gdb initialization takes more than one minute at 100% CPU
       [not found]   ` <CA++fsGG4YuTtb2VC9R+GRcPN5+JSaKpkb+uO3WAX0+VXmh8HDQ@mail.gmail.com>
@ 2012-01-23  9:21     ` Glenn Morris
  2012-01-25  0:37       ` Glenn Morris
  0 siblings, 1 reply; 48+ messages in thread
From: Glenn Morris @ 2012-01-23  9:21 UTC (permalink / raw)
  To: Dov Grobgeld; +Cc: 10580


(Please keep 10580@debbugs.gnu.org cc'd.)

Dov Grobgeld wrote (on Mon, 23 Jan 2012 at 08:36 +0200):

> Thanks for your reply Glenn. Is there a public bugzilla like site for
> emacs bugs or are they managed in email only. I have additional
> problems with gdb in emacs 24 and I would like to know if the problems
> have been reported.

You should have received this email acknowledgement of your report:

http://debbugs.gnu.org/cgi/bugreport.cgi?msg=4;bug=10580

which contains a URL pointing to your report. From there you can
easily find the front page: http://debbugs.gnu.org

> I tried again with emacs -Q and the same thing happens. To be more
> precise the startup time is about 40s at 100% CPU. Here is the output
> from `report-emacs bug` when running with 'emacs -Q'.
> 
> In GNU Emacs 24.0.92.1 (i686-pc-linux-gnu, GTK+ Version 2.22.0)
>  of 2012-01-22 on dovg32
> Windowing system distributor `Fedora Project', version 11.0.10905000
> configured using `configure  '--prefix=/usr/local/public-dev''
> 
> Important settings:
>   value of $LC_ALL: nil
>   value of $LC_COLLATE: nil
>   value of $LC_CTYPE: nil
>   value of $LC_MESSAGES: nil
>   value of $LC_MONETARY: nil
>   value of $LC_NUMERIC: nil
>   value of $LC_TIME: nil
>   value of $LANG: nil
>   value of $XMODIFIERS: @im=none
>   locale-coding-system: nil
>   default enable-multibyte-characters: t
> 
> Major mode: Debugger
> 
> Minor modes in effect:
>   tooltip-mode: t
>   mouse-wheel-mode: t
>   tool-bar-mode: t
>   menu-bar-mode: t
>   file-name-shadow-mode: t
>   global-font-lock-mode: t
>   font-lock-mode: t
>   blink-cursor-mode: t
>   auto-composition-mode: t
>   auto-encryption-mode: t
>   auto-compression-mode: t
>   line-number-mode: t
>   transient-mark-mode: t
> 
> Recent input:
> <help-echo> C-x C-f C-a C-y C-k <S-insert> C-a C-k
> <help-echo> <S-insert> C-a C-k <help-echo> <down-mouse-2>
> <mouse-2> <help-echo> <help-echo> <help-echo> <return>
> M-x g d b <return> <backspace> <backspace> <backspace>
> <backspace> <backspace> <backspace> <backspace> <backspace>
> <backspace> <backspace> <backspace> <backspace> B i
> n L <tab> 3 2 <tab> S o <tab> <return> <help-echo>
> <help-echo> <help-echo> <help-echo> <help-echo> <help-echo>
> C-x k <return> y e s <return> M-x M-p <return> <return>
> M-x g d b <tab> <backspace> <backspace> <backspace>
> b u g <tab> <C-backspace> <C-backspace> r e p <tab>
> o r <tab> <return>
> 
> Recent messages:
> For information about GNU Emacs and the GNU system, type C-h C-a.
> current-kill: Kill ring is empty
> Making completion list...
> 
> Load-path shadows:
> None found.
> 
> Features:
> (shadow sort gnus-util mail-extr message format-spec rfc822 mml mml-sec
> mm-decode mm-bodies mm-encode mail-parse rfc2231 rfc2047 rfc2045
> ietf-drums mm-util mail-prsvr mailabbrev mail-utils gmm-utils mailheader
> emacsbug help-mode easymenu view gdb-mi bindat json gud easy-mmode
> comint ring dired regexp-opt time-date tooltip ediff-hook vc-hooks
> lisp-float-type mwheel x-win x-dnd tool-bar dnd fontset image fringe
> lisp-mode register page menu-bar rfn-eshadow timer select scroll-bar
> mouse jit-lock font-lock syntax facemenu font-core frame cham georgian
> utf-8-lang misc-lang vietnamese tibetan thai tai-viet lao korean
> japanese hebrew greek romanian slovak czech european ethiopic indian
> cyrillic chinese case-table epa-hook jka-cmpr-hook help simple abbrev
> minibuffer loaddefs button faces cus-face files text-properties overlay
> sha1 md5 base64 format env code-pages mule custom widget
> hashtable-print-readable backquote make-network-process dynamic-setting
> system-font-setting font-render-setting move-toolbar gtk x-toolkit x
> multi-tty emacs)





^ permalink raw reply	[flat|nested] 48+ messages in thread

* bug#10580: 24.0.92; gdb initialization takes more than one minute at 100% CPU
  2012-01-23  9:21     ` Glenn Morris
@ 2012-01-25  0:37       ` Glenn Morris
  2012-01-25  8:49         ` Dov Grobgeld
  0 siblings, 1 reply; 48+ messages in thread
From: Glenn Morris @ 2012-01-25  0:37 UTC (permalink / raw)
  To: Dov Grobgeld; +Cc: 10580


>> I tried again with emacs -Q and the same thing happens. To be more
>> precise the startup time is about 40s at 100% CPU.

Is this with everything you try to debug, or just certain things?

Can you try M-x toggle-debug-on-quit, then interrupt Emacs with ctrl-g
during those 40 seconds and see if you get a backtrace?

Or try M-x edebug-defun on the `gdb' function, step through it, and see
what is taking the time.

Guesses: do you have a huge .gdb_history or ~/.gdbinit file?





^ permalink raw reply	[flat|nested] 48+ messages in thread

* bug#10580: 24.0.92; gdb initialization takes more than one minute at 100% CPU
  2012-01-25  0:37       ` Glenn Morris
@ 2012-01-25  8:49         ` Dov Grobgeld
  2012-01-25  9:39           ` Dov Grobgeld
  0 siblings, 1 reply; 48+ messages in thread
From: Dov Grobgeld @ 2012-01-25  8:49 UTC (permalink / raw)
  To: Glenn Morris; +Cc: 10580

[-- Attachment #1: Type: text/plain, Size: 1101 bytes --]

Here are some more tests:

1. It doesn't get stuck when debugging a "hello-world.c" program. Thus it
depends on the executable.
2. Regarding toggle-debug-on-quit and C-g, it doesn't work. No backtrace is
produced and the CPU continues to be at 100%.
3. I tried running edebug on gdb, which wasn't easy. I had to manually
first do eval-buffer on gdb-mi.el and gud.el. But in the end I managed and
found that the CPU is spend during (run-hooks 'gdb-mode-hook) . I'll try to
investigate it further in the next few days.

Regards,
Dov

On Wed, Jan 25, 2012 at 02:37, Glenn Morris <rgm@gnu.org> wrote:

>
> >> I tried again with emacs -Q and the same thing happens. To be more
> >> precise the startup time is about 40s at 100% CPU.
>
> Is this with everything you try to debug, or just certain things?
>
> Can you try M-x toggle-debug-on-quit, then interrupt Emacs with ctrl-g
> during those 40 seconds and see if you get a backtrace?
>
> Or try M-x edebug-defun on the `gdb' function, step through it, and see
> what is taking the time.
>
> Guesses: do you have a huge .gdb_history or ~/.gdbinit file?
>

[-- Attachment #2: Type: text/html, Size: 1528 bytes --]

^ permalink raw reply	[flat|nested] 48+ messages in thread

* bug#10580: 24.0.92; gdb initialization takes more than one minute at 100% CPU
  2012-01-25  8:49         ` Dov Grobgeld
@ 2012-01-25  9:39           ` Dov Grobgeld
  2012-01-25 19:05             ` Glenn Morris
  0 siblings, 1 reply; 48+ messages in thread
From: Dov Grobgeld @ 2012-01-25  9:39 UTC (permalink / raw)
  To: Glenn Morris; +Cc: 10580

[-- Attachment #1: Type: text/plain, Size: 1693 bytes --]

More tests.

1. I was mistaken in my previous email, the CPU spending was triggered
before gdb-mode-hook.
2. The following command in gdb-input starts the 40s 100% CPU:

  (process-send-string (get-buffer-process gud-comint-buffer)
               (concat command "\n")))

where command="1-inferior-tty-set /dev/pts/9". Note that the command
returns immediately, but some other thread apparently gets very busy.

Is this enough info, or do you want me to probe deeper?

On Wed, Jan 25, 2012 at 10:49, Dov Grobgeld <dov.grobgeld@gmail.com> wrote:

> Here are some more tests:
>
> 1. It doesn't get stuck when debugging a "hello-world.c" program. Thus it
> depends on the executable.
> 2. Regarding toggle-debug-on-quit and C-g, it doesn't work. No backtrace
> is produced and the CPU continues to be at 100%.
> 3. I tried running edebug on gdb, which wasn't easy. I had to manually
> first do eval-buffer on gdb-mi.el and gud.el. But in the end I managed and
> found that the CPU is spend during (run-hooks 'gdb-mode-hook) . I'll try to
> investigate it further in the next few days.
>
> Regards,
> Dov
>
> On Wed, Jan 25, 2012 at 02:37, Glenn Morris <rgm@gnu.org> wrote:
>
>>
>> >> I tried again with emacs -Q and the same thing happens. To be more
>> >> precise the startup time is about 40s at 100% CPU.
>>
>> Is this with everything you try to debug, or just certain things?
>>
>> Can you try M-x toggle-debug-on-quit, then interrupt Emacs with ctrl-g
>> during those 40 seconds and see if you get a backtrace?
>>
>> Or try M-x edebug-defun on the `gdb' function, step through it, and see
>> what is taking the time.
>>
>> Guesses: do you have a huge .gdb_history or ~/.gdbinit file?
>>
>
>

[-- Attachment #2: Type: text/html, Size: 2489 bytes --]

^ permalink raw reply	[flat|nested] 48+ messages in thread

* bug#10580: 24.0.92; gdb initialization takes more than one minute at 100% CPU
  2012-01-25  9:39           ` Dov Grobgeld
@ 2012-01-25 19:05             ` Glenn Morris
  2012-04-30  5:33               ` Dov Grobgeld
  0 siblings, 1 reply; 48+ messages in thread
From: Glenn Morris @ 2012-01-25 19:05 UTC (permalink / raw)
  To: Dov Grobgeld; +Cc: 10580

Dov Grobgeld wrote:

> 2. The following command in gdb-input starts the 40s 100% CPU:
>
>   (process-send-string (get-buffer-process gud-comint-buffer)
>                (concat command "\n")))
>
> where command="1-inferior-tty-set /dev/pts/9". Note that the command
> returns immediately, but some other thread apparently gets very busy.

Thanks for the detective work. I'm afraid I don't know what to do about
this. It looks like process handling is messed up somehow.

I hope someone else on this list can help you further.





^ permalink raw reply	[flat|nested] 48+ messages in thread

* bug#10580: 24.0.92; gdb initialization takes more than one minute at 100% CPU
  2012-01-25 19:05             ` Glenn Morris
@ 2012-04-30  5:33               ` Dov Grobgeld
  2012-04-30  6:36                 ` Dov Grobgeld
  0 siblings, 1 reply; 48+ messages in thread
From: Dov Grobgeld @ 2012-04-30  5:33 UTC (permalink / raw)
  To: Glenn Morris; +Cc: 10580

I finally ran emacs-24 under debugger to figure out where it got
stuck. What I found was that it is stuck in keyboard.c where in
read_key_sequence() the control keeps jumping back to the
replay_sequence label. Does this ring a bell to someone?

Regards,
Dov


On Wed, Jan 25, 2012 at 21:05, Glenn Morris <rgm@gnu.org> wrote:
> Dov Grobgeld wrote:
>
>> 2. The following command in gdb-input starts the 40s 100% CPU:
>>
>>   (process-send-string (get-buffer-process gud-comint-buffer)
>>                (concat command "\n")))
>>
>> where command="1-inferior-tty-set /dev/pts/9". Note that the command
>> returns immediately, but some other thread apparently gets very busy.
>
> Thanks for the detective work. I'm afraid I don't know what to do about
> this. It looks like process handling is messed up somehow.
>
> I hope someone else on this list can help you further.





^ permalink raw reply	[flat|nested] 48+ messages in thread

* bug#10580: 24.0.92; gdb initialization takes more than one minute at 100% CPU
  2012-04-30  5:33               ` Dov Grobgeld
@ 2012-04-30  6:36                 ` Dov Grobgeld
  2012-05-06  4:13                   ` Chong Yidong
  0 siblings, 1 reply; 48+ messages in thread
From: Dov Grobgeld @ 2012-04-30  6:36 UTC (permalink / raw)
  To: Glenn Morris; +Cc: 10580

Here is some more clarification. In keyboard.c:command_loop_1() the
line i=read_key_sequence() blocks during interactive work until a key
is pressed. But when the process is stuck in "gdb" read_key_sequence()
does not block but keeps returning. I still have no clue of what goes
on though.

On Mon, Apr 30, 2012 at 08:33, Dov Grobgeld <dov.grobgeld@gmail.com> wrote:
> I finally ran emacs-24 under debugger to figure out where it got
> stuck. What I found was that it is stuck in keyboard.c where in
> read_key_sequence() the control keeps jumping back to the
> replay_sequence label. Does this ring a bell to someone?
>
> Regards,
> Dov
>
>
> On Wed, Jan 25, 2012 at 21:05, Glenn Morris <rgm@gnu.org> wrote:
>> Dov Grobgeld wrote:
>>
>>> 2. The following command in gdb-input starts the 40s 100% CPU:
>>>
>>>   (process-send-string (get-buffer-process gud-comint-buffer)
>>>                (concat command "\n")))
>>>
>>> where command="1-inferior-tty-set /dev/pts/9". Note that the command
>>> returns immediately, but some other thread apparently gets very busy.
>>
>> Thanks for the detective work. I'm afraid I don't know what to do about
>> this. It looks like process handling is messed up somehow.
>>
>> I hope someone else on this list can help you further.





^ permalink raw reply	[flat|nested] 48+ messages in thread

* bug#10580: 24.0.92; gdb initialization takes more than one minute at 100% CPU
  2012-04-30  6:36                 ` Dov Grobgeld
@ 2012-05-06  4:13                   ` Chong Yidong
  2012-05-06  4:55                     ` Dov Grobgeld
  0 siblings, 1 reply; 48+ messages in thread
From: Chong Yidong @ 2012-05-06  4:13 UTC (permalink / raw)
  To: Dov Grobgeld; +Cc: 10580

Dov Grobgeld <dov.grobgeld@gmail.com> writes:

> Here is some more clarification. In keyboard.c:command_loop_1() the
> line i=read_key_sequence() blocks during interactive work until a key
> is pressed. But when the process is stuck in "gdb" read_key_sequence()
> does not block but keeps returning. I still have no clue of what goes
> on though.

Is this still with 24.0.92, or the latest pretest 24.0.96, or the
emacs-24 branch?  I made some changes to the pty handling a few weeks
ago (which should be included in 24.0.96), which may impact this issue.





^ permalink raw reply	[flat|nested] 48+ messages in thread

* bug#10580: 24.0.92; gdb initialization takes more than one minute at 100% CPU
  2012-05-06  4:13                   ` Chong Yidong
@ 2012-05-06  4:55                     ` Dov Grobgeld
  2012-05-06  5:39                       ` Chong Yidong
  0 siblings, 1 reply; 48+ messages in thread
From: Dov Grobgeld @ 2012-05-06  4:55 UTC (permalink / raw)
  To: Chong Yidong; +Cc: 10580

[-- Attachment #1: Type: text/plain, Size: 1270 bytes --]

Thank you very much for looking into this. For me, this is currently, the
main show stopper for starting to emacs-24.

I have just tested the same scenario with the latest git HEAD version from
http://git.savannah.gnu.org/r/emacs.git/ :

823d681 Optionally include holidays in cal-html output

and unfortunately the exact same behavior as before still remains.

Please let me know if there are any tests or debug info that I can provide
you with that can help in resolving this issue. I tried debugging it
myself, but I found it to complex since I lack the knowledge of how
sub-processes are handled in emacs.

Regards,
Dov

On Sun, May 6, 2012 at 7:13 AM, Chong Yidong <cyd@gnu.org> wrote:

> Dov Grobgeld <dov.grobgeld@gmail.com> writes:
>
> > Here is some more clarification. In keyboard.c:command_loop_1() the
> > line i=read_key_sequence() blocks during interactive work until a key
> > is pressed. But when the process is stuck in "gdb" read_key_sequence()
> > does not block but keeps returning. I still have no clue of what goes
> > on though.
>
> Is this still with 24.0.92, or the latest pretest 24.0.96, or the
> emacs-24 branch?  I made some changes to the pty handling a few weeks
> ago (which should be included in 24.0.96), which may impact this issue.
>

[-- Attachment #2: Type: text/html, Size: 1801 bytes --]

^ permalink raw reply	[flat|nested] 48+ messages in thread

* bug#10580: 24.0.92; gdb initialization takes more than one minute at 100% CPU
  2012-05-06  4:55                     ` Dov Grobgeld
@ 2012-05-06  5:39                       ` Chong Yidong
  2012-05-06  7:06                         ` Dov Grobgeld
  0 siblings, 1 reply; 48+ messages in thread
From: Chong Yidong @ 2012-05-06  5:39 UTC (permalink / raw)
  To: Dov Grobgeld; +Cc: 10580

Dov Grobgeld <dov.grobgeld@gmail.com> writes:

> Please let me know if there are any tests or debug info that I can
> provide you with that can help in resolving this issue. I tried
> debugging it myself, but I found it to complex since I lack the
> knowledge of how sub-processes are handled in emacs.

If you look at the *input/output of a.out* buffer, does it contain any
text?

Also, when you say that read_key_sequence keeps returning, what is its
return value?  Also, when read_key_sequence returns early, what is the
value returned by read_char at keyboard.c:9341?

Also, is it possible for you to provide a copy of the problematic
program, or is it not allowed?





^ permalink raw reply	[flat|nested] 48+ messages in thread

* bug#10580: 24.0.92; gdb initialization takes more than one minute at 100% CPU
  2012-05-06  5:39                       ` Chong Yidong
@ 2012-05-06  7:06                         ` Dov Grobgeld
  2012-05-07  2:53                           ` Chong Yidong
  0 siblings, 1 reply; 48+ messages in thread
From: Dov Grobgeld @ 2012-05-06  7:06 UTC (permalink / raw)
  To: Chong Yidong; +Cc: 10580

[-- Attachment #1: Type: text/plain, Size: 3337 bytes --]

The *input/output of a.out* is empty.

It seems that I was wrong about read_key_sequence(). It doesn't "return
early". Here is a stack trace during the timeout:

#0  0x00110424 in __kernel_vsyscall ()
#1  0x005f288d in ___newselect_nocancel () at
../sysdeps/unix/syscall-template.S:82
#2  0x08149691 in xg_select (max_fds=17, rfds=0xbfffe860, wfds=0xbfffe7e0,
efds=0x0, timeout=0xbfffe7d4) at xgselect.c:100
#3  0x0821ffb0 in wait_reading_process_output (time_limit=30, microsecs=0,
read_kbd=-1, do_display=1, wait_for_cell=138903722, wait_proc=0x0,
just_wait_proc=0) at process.c:4620
#4  0x080601c7 in sit_for (timeout=120, reading=1, do_display=1) at
dispnew.c:6068
#5  0x08159606 in read_char (commandflag=1, nmaps=3, maps=0xbfffec50,
prev_event=138903722, used_mouse_menu=0xbfffed18, end_time=0x0) at
keyboard.c:2698
#6  0x08163f12 in read_key_sequence (keybuf=0xbfffee94, bufsize=30,
prompt=138903722, dont_downcase_last=0, can_return_switch_frame=1,
fix_current_buffer=1) at keyboard.c:9341
#7  0x08157472 in command_loop_1 () at keyboard.c:1455
#8  0x081d629d in internal_condition_case (bfun=0x815711b <command_loop_1>,
handlers=138934706, hfun=0x8156ad5 <cmd_error>) at eval.c:1448
#9  0x08156e49 in command_loop_2 (ignore=138903722) at keyboard.c:1160
#10 0x081d5d6f in internal_catch (tag=138932706, func=0x8156e25
<command_loop_2>, arg=138903722) at eval.c:1205
#11 0x08156e05 in command_loop () at keyboard.c:1139
#12 0x0815670e in recursive_edit_1 () at keyboard.c:759
#13 0x0815685f in Frecursive_edit () at keyboard.c:823
#14 0x08154d65 in main (argc=1, argv=0xbffff5e4) at emacs.c:1711

read_char() returns 158534621.

Sorry, I can't redistribute the executable. If the problem can't be solved
by otherwise, I'll try to generate another executable that has this
problem. In any case, here is the output when running gdb from the command
line on the executable.

> gdb -i=mi SolarJet
=thread-group-added,id="i1"
~"GNU gdb (GDB) Fedora (7.2-52.fc14)\n"
~"Copyright (C) 2010 Free Software Foundation, Inc.\n"
~"License GPLv3+: GNU GPL version 3 or later <
http://gnu.org/licenses/gpl.html>\nThis is free software: you are free to
change and redistribute it.\nThere is NO WARRANTY, to the extent permitted
by law.  Type \"show copying\"\nand \"show warranty\" for details.\n"
~"This GDB was configured as \"i686-redhat-linux-gnu\".\nFor bug reporting
instructions, please see:\n"
~"<http://www.gnu.org/software/gdb/bugs/>...\n"
~"Reading symbols from
/mnt/fdrive/git/SolarJet/Apps/SolarJet/Project/qt/BinLinux32/SolarJet..."
~"done.\n"
(gdb)

Thanks,
Dov

On Sun, May 6, 2012 at 8:39 AM, Chong Yidong <cyd@gnu.org> wrote:

> Dov Grobgeld <dov.grobgeld@gmail.com> writes:
>
> > Please let me know if there are any tests or debug info that I can
> > provide you with that can help in resolving this issue. I tried
> > debugging it myself, but I found it to complex since I lack the
> > knowledge of how sub-processes are handled in emacs.
>
> If you look at the *input/output of a.out* buffer, does it contain any
> text?
>
> Also, when you say that read_key_sequence keeps returning, what is its
> return value?  Also, when read_key_sequence returns early, what is the
> value returned by read_char at keyboard.c:9341?
>
> Also, is it possible for you to provide a copy of the problematic
> program, or is it not allowed?
>

[-- Attachment #2: Type: text/html, Size: 4185 bytes --]

^ permalink raw reply	[flat|nested] 48+ messages in thread

* bug#10580: 24.0.92; gdb initialization takes more than one minute at 100% CPU
  2012-05-06  7:06                         ` Dov Grobgeld
@ 2012-05-07  2:53                           ` Chong Yidong
  2012-05-07  5:07                             ` Dov Grobgeld
  0 siblings, 1 reply; 48+ messages in thread
From: Chong Yidong @ 2012-05-07  2:53 UTC (permalink / raw)
  To: Dov Grobgeld; +Cc: 10580

Dov Grobgeld <dov.grobgeld@gmail.com> writes:

> The *input/output of a.out* is empty.
>
> It seems that I was wrong about read_key_sequence(). It doesn't
> "return early".

During this time, is Emacs responsive to user commands, i.e. does it
work normally apart from taking 100% CPU?  Or is it just unresponsive?

Also, what is your gdb version?

Also, please set a breakpoint at process.c:4896, which should be the
line

		  struct Lisp_Process *p = XPROCESS (proc);

as well as the function exec_sentinel().  See if Emacs hits each
breakpoint, and step through it for the next several steps.  In
exec_sentinel, please show the Lisp values of the `proc' and `reason'
variables (i.e. `pp proc' and `pp reason'.)

Basically, gdb-mi.el allocates a pty and passes it to the gdb process,
which hooks the pty up to the debugged process's input/output.  That's
what the "1-inferior-tty-set /dev/pts/9" gdb command does.  Emacs then
listens for input/output on the pty.  Recently I fixed a bug in which
Emacs would use 100% CPU due to Emacs getting an EIO error on that pty
and then spinning; this fix involved setting up a sentinel that closes
the pty when Emacs gets EIO; it's possible the fix is not working for
you, though I don't know why.  The other possibility is that the program
you are debugging does something strange with its input/output stream.

Thanks.





^ permalink raw reply	[flat|nested] 48+ messages in thread

* bug#10580: 24.0.92; gdb initialization takes more than one minute at 100% CPU
  2012-05-07  2:53                           ` Chong Yidong
@ 2012-05-07  5:07                             ` Dov Grobgeld
  2012-05-07  6:11                               ` Chong Yidong
  0 siblings, 1 reply; 48+ messages in thread
From: Dov Grobgeld @ 2012-05-07  5:07 UTC (permalink / raw)
  To: Chong Yidong; +Cc: 10580

[-- Attachment #1: Type: text/plain, Size: 2000 bytes --]

Hi Chong,

In response to your questions.

During the "100% CPU" time period, emacs still responds normally and files
can be opened, etc.

My gdb version is "GNU gdb (GDB) Fedora (7.2-52.fc14)". I have tried it at
home as well with a later version from Fedora 16 and the result is the same.

I put breakpoints at the lines that you indicated, but as you suspected,
the breakpoints are only reached when I exit gdb with the "quit" command.

What's next? Thanks again for looking into this.

Dov




On Mon, May 7, 2012 at 5:53 AM, Chong Yidong <cyd@gnu.org> wrote:

> Dov Grobgeld <dov.grobgeld@gmail.com> writes:
>
> > The *input/output of a.out* is empty.
> >
> > It seems that I was wrong about read_key_sequence(). It doesn't
> > "return early".
>
> During this time, is Emacs responsive to user commands, i.e. does it
> work normally apart from taking 100% CPU?  Or is it just unresponsive?
>
> Also, what is your gdb version?
>
> Also, please set a breakpoint at process.c:4896, which should be the
> line
>
>                  struct Lisp_Process *p = XPROCESS (proc);
>
> as well as the function exec_sentinel().  See if Emacs hits each
> breakpoint, and step through it for the next several steps.  In
> exec_sentinel, please show the Lisp values of the `proc' and `reason'
> variables (i.e. `pp proc' and `pp reason'.)
>
> Basically, gdb-mi.el allocates a pty and passes it to the gdb process,
> which hooks the pty up to the debugged process's input/output.  That's
> what the "1-inferior-tty-set /dev/pts/9" gdb command does.  Emacs then
> listens for input/output on the pty.  Recently I fixed a bug in which
> Emacs would use 100% CPU due to Emacs getting an EIO error on that pty
> and then spinning; this fix involved setting up a sentinel that closes
> the pty when Emacs gets EIO; it's possible the fix is not working for
> you, though I don't know why.  The other possibility is that the program
> you are debugging does something strange with its input/output stream.
>
> Thanks.
>

[-- Attachment #2: Type: text/html, Size: 2654 bytes --]

^ permalink raw reply	[flat|nested] 48+ messages in thread

* bug#10580: 24.0.92; gdb initialization takes more than one minute at 100% CPU
  2012-05-07  5:07                             ` Dov Grobgeld
@ 2012-05-07  6:11                               ` Chong Yidong
  2012-05-07  6:26                                 ` Chong Yidong
  0 siblings, 1 reply; 48+ messages in thread
From: Chong Yidong @ 2012-05-07  6:11 UTC (permalink / raw)
  To: Dov Grobgeld; +Cc: 10580

Dov Grobgeld <dov.grobgeld@gmail.com> writes:

> I put breakpoints at the lines that you indicated, but as you
> suspected, the breakpoints are only reached when I exit gdb with the
> "quit" command.
>
> What's next? Thanks again for looking into this.

Please apply the following patch, then, when Emacs is taking 100% CPU,
set a breakpoint at process.c:4854, i.e. at

		if (p->pid == -2)
		  ;

This captures the state just after Emacs calls read_process_output on
the pty passed to your program.  If this breakpoint is triggered, please
report the value of nread and errno, and step through to the end of the
subsequent if/else block and report the gdb session.  Thanks.


=== modified file 'src/process.c'
*** src/process.c	2012-04-20 06:39:29 +0000
--- src/process.c	2012-05-07 06:09:25 +0000
***************
*** 4847,4852 ****
--- 4847,4859 ----
  		 buffered-ahead character if we have one.  */
  
  	      nread = read_process_output (proc, channel);
+ 
+ 	      {
+ 		struct Lisp_Process *p = XPROCESS (proc);
+ 		if (p->pid == -2)
+ 		  ;
+ 	      }
+ 
  	      if (nread > 0)
  		{
  		  /* Since read_process_output can run a filter,






^ permalink raw reply	[flat|nested] 48+ messages in thread

* bug#10580: 24.0.92; gdb initialization takes more than one minute at 100% CPU
  2012-05-07  6:11                               ` Chong Yidong
@ 2012-05-07  6:26                                 ` Chong Yidong
  2012-05-08  5:33                                   ` Dov Grobgeld
  0 siblings, 1 reply; 48+ messages in thread
From: Chong Yidong @ 2012-05-07  6:26 UTC (permalink / raw)
  To: Dov Grobgeld; +Cc: 10580

Actually, try the following patch instead (apparently gdb has some
issues with printing errno).  Apply the patch, then when Emacs is taking
100% CPU do an interrupt and set the breakpoint at process.c:4855, then
when the breakpoint triggers do

n
p nread
p errno

and step through the subsequent if/else blocks.  Thanks.

Basically, the 100% CPU appears to be because Emacs' select() call keeps
getting worken up by the pty attached to your program.  But, for some
reason, no actual output being read from that pty.  These debugging
steps are trying to figure out if some uncaught errno is being reported
by the pty read.


=== modified file 'src/process.c'
*** src/process.c	2012-04-20 06:39:29 +0000
--- src/process.c	2012-05-07 06:21:39 +0000
***************
*** 4822,4827 ****
--- 4822,4829 ----
                && !FD_ISSET (channel, &non_process_wait_mask))
  	    {
  	      int nread;
+ 	      int saved_errno = 0;
+ 	      struct Lisp_Process *pp;
  
  	      /* If waiting for this channel, arrange to return as
  		 soon as no more input to be processed.  No more
***************
*** 4847,4852 ****
--- 4849,4859 ----
  		 buffered-ahead character if we have one.  */
  
  	      nread = read_process_output (proc, channel);
+ 
+ 	      pp = XPROCESS (proc);
+ 	      if (pp->pid == -2)
+ 		saved_errno = errno;
+ 
  	      if (nread > 0)
  		{
  		  /* Since read_process_output can run a filter,






^ permalink raw reply	[flat|nested] 48+ messages in thread

* bug#10580: 24.0.92; gdb initialization takes more than one minute at 100% CPU
  2012-05-07  6:26                                 ` Chong Yidong
@ 2012-05-08  5:33                                   ` Dov Grobgeld
  2012-05-08  7:56                                     ` Dov Grobgeld
  0 siblings, 1 reply; 48+ messages in thread
From: Dov Grobgeld @ 2012-05-08  5:33 UTC (permalink / raw)
  To: Chong Yidong; +Cc: 10580

[-- Attachment #1: Type: text/plain, Size: 2062 bytes --]

I added the above patch and the result is as follows:

After the following two lines:

    nread = read_process_output (proc, channel);

    pp = XPROCESS(proc);

nread==4095, pp->pid=1234 repeatedly. (Actually 1234 seems to be an
arbitrary, but constant number between 1000 and 2000).

This seems strange, as obviously the sub-process does not produce 4095
characters repeatedly.

Thanks,
Dov

On Mon, May 7, 2012 at 9:26 AM, Chong Yidong <cyd@gnu.org> wrote:

> Actually, try the following patch instead (apparently gdb has some
> issues with printing errno).  Apply the patch, then when Emacs is taking
> 100% CPU do an interrupt and set the breakpoint at process.c:4855, then
> when the breakpoint triggers do
>
> n
> p nread
> p errno
>
> and step through the subsequent if/else blocks.  Thanks.
>
> Basically, the 100% CPU appears to be because Emacs' select() call keeps
> getting worken up by the pty attached to your program.  But, for some
> reason, no actual output being read from that pty.  These debugging
> steps are trying to figure out if some uncaught errno is being reported
> by the pty read.
>
>
> === modified file 'src/process.c'
> *** src/process.c       2012-04-20 06:39:29 +0000
> --- src/process.c       2012-05-07 06:21:39 +0000
> ***************
> *** 4822,4827 ****
> --- 4822,4829 ----
>                && !FD_ISSET (channel, &non_process_wait_mask))
>            {
>              int nread;
> +             int saved_errno = 0;
> +             struct Lisp_Process *pp;
>
>              /* If waiting for this channel, arrange to return as
>                 soon as no more input to be processed.  No more
> ***************
> *** 4847,4852 ****
> --- 4849,4859 ----
>                  buffered-ahead character if we have one.  */
>
>              nread = read_process_output (proc, channel);
> +
> +             pp = XPROCESS (proc);
> +             if (pp->pid == -2)
> +               saved_errno = errno;
> +
>              if (nread > 0)
>                {
>                  /* Since read_process_output can run a filter,
>
>

[-- Attachment #2: Type: text/html, Size: 2841 bytes --]

^ permalink raw reply	[flat|nested] 48+ messages in thread

* bug#10580: 24.0.92; gdb initialization takes more than one minute at 100% CPU
  2012-05-08  5:33                                   ` Dov Grobgeld
@ 2012-05-08  7:56                                     ` Dov Grobgeld
  2012-05-08  8:28                                       ` Chong Yidong
  0 siblings, 1 reply; 48+ messages in thread
From: Dov Grobgeld @ 2012-05-08  7:56 UTC (permalink / raw)
  To: Chong Yidong; +Cc: 10580

[-- Attachment #1: Type: text/plain, Size: 2493 bytes --]

Some more info that I found through strace that might help. Alltogether
read_process_output() is called 214 times and thus a total of 870k of text
is read through /dev/ptmx to read_process_output() . Could the amount of
data possibly explain the slowness?

Regards,
Dov

On Tue, May 8, 2012 at 8:33 AM, Dov Grobgeld <dov.grobgeld@gmail.com> wrote:

> I added the above patch and the result is as follows:
>
> After the following two lines:
>
>
>     nread = read_process_output (proc, channel);
>
>     pp = XPROCESS(proc);
>
> nread==4095, pp->pid=1234 repeatedly. (Actually 1234 seems to be an
> arbitrary, but constant number between 1000 and 2000).
>
> This seems strange, as obviously the sub-process does not produce 4095
> characters repeatedly.
>
> Thanks,
> Dov
>
> On Mon, May 7, 2012 at 9:26 AM, Chong Yidong <cyd@gnu.org> wrote:
>
>> Actually, try the following patch instead (apparently gdb has some
>> issues with printing errno).  Apply the patch, then when Emacs is taking
>> 100% CPU do an interrupt and set the breakpoint at process.c:4855, then
>> when the breakpoint triggers do
>>
>> n
>> p nread
>> p errno
>>
>> and step through the subsequent if/else blocks.  Thanks.
>>
>> Basically, the 100% CPU appears to be because Emacs' select() call keeps
>> getting worken up by the pty attached to your program.  But, for some
>> reason, no actual output being read from that pty.  These debugging
>> steps are trying to figure out if some uncaught errno is being reported
>> by the pty read.
>>
>>
>> === modified file 'src/process.c'
>> *** src/process.c       2012-04-20 06:39:29 +0000
>> --- src/process.c       2012-05-07 06:21:39 +0000
>> ***************
>> *** 4822,4827 ****
>> --- 4822,4829 ----
>>                && !FD_ISSET (channel, &non_process_wait_mask))
>>            {
>>              int nread;
>> +             int saved_errno = 0;
>> +             struct Lisp_Process *pp;
>>
>>              /* If waiting for this channel, arrange to return as
>>                 soon as no more input to be processed.  No more
>> ***************
>> *** 4847,4852 ****
>> --- 4849,4859 ----
>>                  buffered-ahead character if we have one.  */
>>
>>              nread = read_process_output (proc, channel);
>> +
>> +             pp = XPROCESS (proc);
>> +             if (pp->pid == -2)
>> +               saved_errno = errno;
>> +
>>              if (nread > 0)
>>                {
>>                  /* Since read_process_output can run a filter,
>>
>>
>

[-- Attachment #2: Type: text/html, Size: 3522 bytes --]

^ permalink raw reply	[flat|nested] 48+ messages in thread

* bug#10580: 24.0.92; gdb initialization takes more than one minute at 100% CPU
  2012-05-08  7:56                                     ` Dov Grobgeld
@ 2012-05-08  8:28                                       ` Chong Yidong
  2012-05-08 11:59                                         ` Dov Grobgeld
  0 siblings, 1 reply; 48+ messages in thread
From: Chong Yidong @ 2012-05-08  8:28 UTC (permalink / raw)
  To: Dov Grobgeld; +Cc: 10580

Dov Grobgeld <dov.grobgeld@gmail.com> writes:

> I added the above patch and the result is as follows:
> After the following two lines:
>
>     nread = read_process_output (proc, channel);
>     pp = XPROCESS(proc);
>
> nread==4095, pp->pid=1234 repeatedly. (Actually 1234 seems to be an
> arbitrary, but constant number between 1000 and 2000). 
>
> Some more info that I found through strace that might help.
> Alltogether read_process_output() is called 214 times and thus a total
> of 870k of text is read through /dev/ptmx to read_process_output() .
> Could the amount of data possibly explain the slowness?

Maybe, if this process IO is emitted non-stop.  But this indicates that
the traffic is due to the main connection with the main gdb process
(which has a positive pid), not with the pty which gdb-mi uses for IO
(which has pid -2) like I guessed.

Could you do

M-: (setq gdb-enable-debug t) RET

and show the value of the variable `gdb-debug-log'?

For example, when I run M-x gdb on the Emacs binary itself,
`gdb-debug-log' gets 22 entries by the time I get to the (gdb) prompt;
this is the usual GDB-MI chatter.  From the time I "run" the program
till the debugged program exits, it gains another 24 entries.  Do you
see a lot more traffic with your program?





^ permalink raw reply	[flat|nested] 48+ messages in thread

* bug#10580: 24.0.92; gdb initialization takes more than one minute at 100% CPU
  2012-05-08  8:28                                       ` Chong Yidong
@ 2012-05-08 11:59                                         ` Dov Grobgeld
  2012-05-08 16:25                                           ` Chong Yidong
  2012-05-08 17:38                                           ` Eli Zaretskii
  0 siblings, 2 replies; 48+ messages in thread
From: Dov Grobgeld @ 2012-05-08 11:59 UTC (permalink / raw)
  To: Chong Yidong; +Cc: 10580

[-- Attachment #1: Type: text/plain, Size: 1686 bytes --]

Indeed, my result is much fatter.

(safe-length gdb-debug-log) => 223

and the total length of the messages is about 800k. So it seems that the
time spent is simply the parsing of this large chunk of data? What gdb
command is run that outputs all the file="..." commands?

Thanks,
Dov

On Tue, May 8, 2012 at 11:28 AM, Chong Yidong <cyd@gnu.org> wrote:

> Dov Grobgeld <dov.grobgeld@gmail.com> writes:
>
> > I added the above patch and the result is as follows:
> > After the following two lines:
> >
> >     nread = read_process_output (proc, channel);
> >     pp = XPROCESS(proc);
> >
> > nread==4095, pp->pid=1234 repeatedly. (Actually 1234 seems to be an
> > arbitrary, but constant number between 1000 and 2000).
> >
> > Some more info that I found through strace that might help.
> > Alltogether read_process_output() is called 214 times and thus a total
> > of 870k of text is read through /dev/ptmx to read_process_output() .
> > Could the amount of data possibly explain the slowness?
>
> Maybe, if this process IO is emitted non-stop.  But this indicates that
> the traffic is due to the main connection with the main gdb process
> (which has a positive pid), not with the pty which gdb-mi uses for IO
> (which has pid -2) like I guessed.
>
> Could you do
>
> M-: (setq gdb-enable-debug t) RET
>
> and show the value of the variable `gdb-debug-log'?
>
> For example, when I run M-x gdb on the Emacs binary itself,
> `gdb-debug-log' gets 22 entries by the time I get to the (gdb) prompt;
> this is the usual GDB-MI chatter.  From the time I "run" the program
> till the debugged program exits, it gains another 24 entries.  Do you
> see a lot more traffic with your program?
>

[-- Attachment #2: Type: text/html, Size: 2293 bytes --]

^ permalink raw reply	[flat|nested] 48+ messages in thread

* bug#10580: 24.0.92; gdb initialization takes more than one minute at 100% CPU
  2012-05-08 11:59                                         ` Dov Grobgeld
@ 2012-05-08 16:25                                           ` Chong Yidong
  2012-05-08 17:47                                             ` Eli Zaretskii
  2012-05-08 17:38                                           ` Eli Zaretskii
  1 sibling, 1 reply; 48+ messages in thread
From: Chong Yidong @ 2012-05-08 16:25 UTC (permalink / raw)
  To: Dov Grobgeld; +Cc: 10580

Dov Grobgeld <dov.grobgeld@gmail.com> writes:

> Indeed, my result is much fatter.
>
> (safe-length gdb-debug-log) => 223
>
> and the total length of the messages is about 800k. So it seems that
> the time spent is simply the parsing of this large chunk of data? What
> gdb command is run that outputs all the file="..." commands?

Those are status messages from turning on GDB's MI (machine interface)
system, I think, though I don't see why it makes so much difference in
your case.

If you type, from the shell,

  gdb -i=mi YOUR-BINARY
  r

do you similarly see a huge output?





^ permalink raw reply	[flat|nested] 48+ messages in thread

* bug#10580: 24.0.92; gdb initialization takes more than one minute at 100% CPU
  2012-05-08 11:59                                         ` Dov Grobgeld
  2012-05-08 16:25                                           ` Chong Yidong
@ 2012-05-08 17:38                                           ` Eli Zaretskii
  1 sibling, 0 replies; 48+ messages in thread
From: Eli Zaretskii @ 2012-05-08 17:38 UTC (permalink / raw)
  To: Dov Grobgeld; +Cc: cyd, 10580

> Date: Tue, 8 May 2012 14:59:36 +0300
> From: Dov Grobgeld <dov.grobgeld@gmail.com>
> Cc: 10580@debbugs.gnu.org
> 
> Indeed, my result is much fatter.
> 
> (safe-length gdb-debug-log) => 223
> 
> and the total length of the messages is about 800k.

Ouch! could you send it as a compressed attachment?  I'd be interested
to see what gdb-mi.el commands generate such large output.





^ permalink raw reply	[flat|nested] 48+ messages in thread

* bug#10580: 24.0.92; gdb initialization takes more than one minute at 100% CPU
  2012-05-08 16:25                                           ` Chong Yidong
@ 2012-05-08 17:47                                             ` Eli Zaretskii
  2012-05-08 21:07                                               ` Dov Grobgeld
  0 siblings, 1 reply; 48+ messages in thread
From: Eli Zaretskii @ 2012-05-08 17:47 UTC (permalink / raw)
  To: Chong Yidong; +Cc: dov.grobgeld, 10580

> From: Chong Yidong <cyd@gnu.org>
> Date: Wed, 09 May 2012 00:25:00 +0800
> Cc: 10580@debbugs.gnu.org
> 
> Those are status messages from turning on GDB's MI (machine interface)
> system, I think, though I don't see why it makes so much difference in
> your case.
> 
> If you type, from the shell,
> 
>   gdb -i=mi YOUR-BINARY
>   r
> 
> do you similarly see a huge output?

As you know, in addition to "run", gdb-mi.el sends lots of other
commands behind the scenes, so the above is not a faithful simulation
of what happens when GDB is run by Emacs.  But I agree that if the
above produces similarly voluminous output, we cannot really blame
gdb-mi.el.






^ permalink raw reply	[flat|nested] 48+ messages in thread

* bug#10580: 24.0.92; gdb initialization takes more than one minute at 100% CPU
  2012-05-08 17:47                                             ` Eli Zaretskii
@ 2012-05-08 21:07                                               ` Dov Grobgeld
  2012-05-08 21:24                                                 ` Andreas Schwab
  0 siblings, 1 reply; 48+ messages in thread
From: Dov Grobgeld @ 2012-05-08 21:07 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: Chong Yidong, 10580

[-- Attachment #1: Type: text/plain, Size: 2222 bytes --]

So my latest investigations suggest that the problem is the
"-file-list-exec-source-files" command which generates the huge output due
to the large number of files that is part of the project.

The following shows the problem from the command line.

echo -file-list-exec-source-files > /tmp/gdb.in
gdb MyExec < /tmp/gdb.in > /tmp/gdb.out
wc /tmp/gdb.out
     11      69 3725105 /tmp/gdb.out

(Note that this is on a my home box, where the output is much larger than
what I reported this morning possibly due to different paths).

So there are still several questions:

* Why does it take several minutes to parse a 3.7M file? Could it be
related to the fact that gdb-mi/emacs concatinates the entire string before
trying to parse it. Still 3.7M is far too much.

* Noted that I can't run gdb MyExec < /tmp/gdb.in in a shell buffer. It
gets slower and slower while the CPU stays at 100%.

* There is a huge redundancy in gdb.out. The command
-file-list-exec-source-files should output all source files included, but
the same source files are listed multiple times. Consider the huge file
size reduction after sorting and uniq'ing:

perl -ne 'while(/(\w+)=\"(.*?)\"/g) { print "$1=$2\n"; }' /tmp/gdb.out |
sort | uniq | wc

   3931    3931  220654

Why doesn't -file-list-exec-source file do uniq internally. This seems like
a bug in gdb.

* Why does gdb-mi.el do -file-list-exec-source-files at all? Can't it
search for source files on demand?

Regards,
Dov

On Tue, May 8, 2012 at 8:47 PM, Eli Zaretskii <eliz@gnu.org> wrote:

> > From: Chong Yidong <cyd@gnu.org>
> > Date: Wed, 09 May 2012 00:25:00 +0800
> > Cc: 10580@debbugs.gnu.org
> >
> > Those are status messages from turning on GDB's MI (machine interface)
> > system, I think, though I don't see why it makes so much difference in
> > your case.
> >
> > If you type, from the shell,
> >
> >   gdb -i=mi YOUR-BINARY
> >   r
> >
> > do you similarly see a huge output?
>
> As you know, in addition to "run", gdb-mi.el sends lots of other
> commands behind the scenes, so the above is not a faithful simulation
> of what happens when GDB is run by Emacs.  But I agree that if the
> above produces similarly voluminous output, we cannot really blame
> gdb-mi.el.
>
>

[-- Attachment #2: Type: text/html, Size: 3109 bytes --]

^ permalink raw reply	[flat|nested] 48+ messages in thread

* bug#10580: 24.0.92; gdb initialization takes more than one minute at 100% CPU
  2012-05-08 21:07                                               ` Dov Grobgeld
@ 2012-05-08 21:24                                                 ` Andreas Schwab
  2012-05-08 21:30                                                   ` Dov Grobgeld
  0 siblings, 1 reply; 48+ messages in thread
From: Andreas Schwab @ 2012-05-08 21:24 UTC (permalink / raw)
  To: Dov Grobgeld; +Cc: Chong Yidong, 10580

Dov Grobgeld <dov.grobgeld@gmail.com> writes:

> * Why does gdb-mi.el do -file-list-exec-source-files at all? Can't it
> search for source files on demand?

Customize gdb-create-source-file-list to nil.

Andreas.

-- 
Andreas Schwab, schwab@linux-m68k.org
GPG Key fingerprint = 58CA 54C7 6D53 942B 1756  01D3 44D5 214B 8276 4ED5
"And now for something completely different."





^ permalink raw reply	[flat|nested] 48+ messages in thread

* bug#10580: 24.0.92; gdb initialization takes more than one minute at 100% CPU
  2012-05-08 21:24                                                 ` Andreas Schwab
@ 2012-05-08 21:30                                                   ` Dov Grobgeld
  2012-05-09  7:47                                                     ` Andreas Schwab
  0 siblings, 1 reply; 48+ messages in thread
From: Dov Grobgeld @ 2012-05-08 21:30 UTC (permalink / raw)
  To: Andreas Schwab; +Cc: Chong Yidong, 10580

[-- Attachment #1: Type: text/plain, Size: 1126 bytes --]

I first that at first too, but then I realized that it doesn't do it. The
gdb-mi.el source has the following logic.

  (gdb-input
                                        ; Needs GDB 6.2 onwards.
   (list "-file-list-exec-source-files" 'gdb-get-source-file-list))
  (if gdb-create-source-file-list
      (gdb-input
                                        ; Needs GDB 6.0 onwards.
       (list "-file-list-exec-source-file" 'gdb-get-source-file)))

i.e. the gdb command "-file-list-exec-source-files" (note the s in files)
is called independantly from gdb-create-source-file-list which only
influences the execution of "-file-list-exec-source-file".

On Wed, May 9, 2012 at 12:24 AM, Andreas Schwab <schwab@linux-m68k.org>wrote:

> Dov Grobgeld <dov.grobgeld@gmail.com> writes:
>
> > * Why does gdb-mi.el do -file-list-exec-source-files at all? Can't it
> > search for source files on demand?
>
> Customize gdb-create-source-file-list to nil.
>
> Andreas.
>
> --
> Andreas Schwab, schwab@linux-m68k.org
> GPG Key fingerprint = 58CA 54C7 6D53 942B 1756  01D3 44D5 214B 8276 4ED5
> "And now for something completely different."
>

[-- Attachment #2: Type: text/html, Size: 1992 bytes --]

^ permalink raw reply	[flat|nested] 48+ messages in thread

* bug#10580: 24.0.92; gdb initialization takes more than one minute at 100% CPU
  2012-05-08 21:30                                                   ` Dov Grobgeld
@ 2012-05-09  7:47                                                     ` Andreas Schwab
  2012-05-09  8:44                                                       ` Dov Grobgeld
  0 siblings, 1 reply; 48+ messages in thread
From: Andreas Schwab @ 2012-05-09  7:47 UTC (permalink / raw)
  To: Dov Grobgeld; +Cc: Chong Yidong, 10580

Dov Grobgeld <dov.grobgeld@gmail.com> writes:

> I first that at first too, but then I realized that it doesn't do it. The
> gdb-mi.el source has the following logic.
>
>   (gdb-input
>                                         ; Needs GDB 6.2 onwards.
>    (list "-file-list-exec-source-files" 'gdb-get-source-file-list))
>   (if gdb-create-source-file-list
>       (gdb-input
>                                         ; Needs GDB 6.0 onwards.
>        (list "-file-list-exec-source-file" 'gdb-get-source-file)))

You are looking at a very old version of gdb-mi.el.

Andreas.

-- 
Andreas Schwab, schwab@linux-m68k.org
GPG Key fingerprint = 58CA 54C7 6D53 942B 1756  01D3 44D5 214B 8276 4ED5
"And now for something completely different."





^ permalink raw reply	[flat|nested] 48+ messages in thread

* bug#10580: 24.0.92; gdb initialization takes more than one minute at 100% CPU
  2012-05-09  7:47                                                     ` Andreas Schwab
@ 2012-05-09  8:44                                                       ` Dov Grobgeld
  2012-05-09 17:36                                                         ` Eli Zaretskii
  0 siblings, 1 reply; 48+ messages in thread
From: Dov Grobgeld @ 2012-05-09  8:44 UTC (permalink / raw)
  To: Andreas Schwab; +Cc: Chong Yidong, 10580

[-- Attachment #1: Type: text/plain, Size: 1604 bytes --]

Yes, sorry. I discovered that I looked at an old version. The latest git
version indeed allows disabling the -file-list-exec-source-files. I will
use that option which indeed is a work around for the problem.

In addition, I filed a bug for gdb that it should uniq the filenames output
by -file-list-exec-source-files.

I realized that all filelist-exec-source-files is used for is to turn on
gdb minor mode for all files that are currently open in emacs. Perhaps we
should turn the problem around by asking for a gdb function that answers
the question whether a file is referenced by an executable. It would then
be possible to loop over the emacs buffers and turn on gdb minor mode if
the file is referenced by the new gdb session.

Regards,
Dov

On Wed, May 9, 2012 at 10:47 AM, Andreas Schwab <schwab@linux-m68k.org>wrote:

> Dov Grobgeld <dov.grobgeld@gmail.com> writes:
>
> > I first that at first too, but then I realized that it doesn't do it. The
> > gdb-mi.el source has the following logic.
> >
> >   (gdb-input
> >                                         ; Needs GDB 6.2 onwards.
> >    (list "-file-list-exec-source-files" 'gdb-get-source-file-list))
> >   (if gdb-create-source-file-list
> >       (gdb-input
> >                                         ; Needs GDB 6.0 onwards.
> >        (list "-file-list-exec-source-file" 'gdb-get-source-file)))
>
> You are looking at a very old version of gdb-mi.el.
>
> Andreas.
>
> --
> Andreas Schwab, schwab@linux-m68k.org
> GPG Key fingerprint = 58CA 54C7 6D53 942B 1756  01D3 44D5 214B 8276 4ED5
> "And now for something completely different."
>

[-- Attachment #2: Type: text/html, Size: 2301 bytes --]

^ permalink raw reply	[flat|nested] 48+ messages in thread

* bug#10580: 24.0.92; gdb initialization takes more than one minute at 100% CPU
  2012-05-09  8:44                                                       ` Dov Grobgeld
@ 2012-05-09 17:36                                                         ` Eli Zaretskii
  2012-05-10  6:00                                                           ` Dov Grobgeld
  0 siblings, 1 reply; 48+ messages in thread
From: Eli Zaretskii @ 2012-05-09 17:36 UTC (permalink / raw)
  To: Dov Grobgeld; +Cc: cyd, schwab, 10580

> Date: Wed, 9 May 2012 11:44:32 +0300
> From: Dov Grobgeld <dov.grobgeld@gmail.com>
> Cc: Eli Zaretskii <eliz@gnu.org>, Chong Yidong <cyd@gnu.org>, 10580@debbugs.gnu.org
> 
> In addition, I filed a bug for gdb that it should uniq the filenames output
> by -file-list-exec-source-files.

Can you provide a link to that bug report?

FWIW, when I use -file-list-exec-source-files while debugging Emacs, I
don't see duplicate file names in the GDB output.  Maybe I'm blind.





^ permalink raw reply	[flat|nested] 48+ messages in thread

* bug#10580: 24.0.92; gdb initialization takes more than one minute at 100% CPU
  2012-05-09 17:36                                                         ` Eli Zaretskii
@ 2012-05-10  6:00                                                           ` Dov Grobgeld
  2012-05-10 14:13                                                             ` Chong Yidong
  2012-05-10 16:32                                                             ` Eli Zaretskii
  0 siblings, 2 replies; 48+ messages in thread
From: Dov Grobgeld @ 2012-05-10  6:00 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: cyd, schwab, 10580

[-- Attachment #1: Type: text/plain, Size: 1514 bytes --]

Here is a link to the gdb bug:

http://sourceware.org/bugzilla/show_bug.cgi?id=14081

I tried running file-list-exec-source-files and I get duplicates as well.
Try the following:

prompt> echo -file-list-exec-source-files > /tmp/gdb.in
prompt> gdb -i=mi emacs < /tmp/gdb.in > /tmp/gdb.out
prompt> perl -ne 'while(/(\w+)=\"(.*?)\"/g) { print "$1=$2\n"; }'
/tmp/gdb.out | sort | head -15
file=alloc.c
file=alloc.c
file=allocator.c
file=atimer.c
file=atimer.c
file=bidi.c
file=bidi.c
file=buffer.c
file=buffer.c
file=buffer.h
file=buffer.h
file=buffer.h
file=buffer.h
file=buffer.h
file=buffer.h

My version of gdb is:

GNU gdb (GDB) Fedora (7.2-52.fc14)

For my executable gdb outputs full paths as well as the fullname field,
which expands the output considerably.

Still, it bothering me the fact that the above perl expression parses the
gdb output in a fraction of a second, (0.01s user time) whereas gdb-mi.el
takes more than 40s.

Regards,
Dov

On Wed, May 9, 2012 at 8:36 PM, Eli Zaretskii <eliz@gnu.org> wrote:

> > Date: Wed, 9 May 2012 11:44:32 +0300
> > From: Dov Grobgeld <dov.grobgeld@gmail.com>
> > Cc: Eli Zaretskii <eliz@gnu.org>, Chong Yidong <cyd@gnu.org>,
> 10580@debbugs.gnu.org
> >
> > In addition, I filed a bug for gdb that it should uniq the filenames
> output
> > by -file-list-exec-source-files.
>
> Can you provide a link to that bug report?
>
> FWIW, when I use -file-list-exec-source-files while debugging Emacs, I
> don't see duplicate file names in the GDB output.  Maybe I'm blind.
>

[-- Attachment #2: Type: text/html, Size: 2400 bytes --]

^ permalink raw reply	[flat|nested] 48+ messages in thread

* bug#10580: 24.0.92; gdb initialization takes more than one minute at 100% CPU
  2012-05-10  6:00                                                           ` Dov Grobgeld
@ 2012-05-10 14:13                                                             ` Chong Yidong
  2012-05-10 19:07                                                               ` Dov Grobgeld
  2012-05-10 16:32                                                             ` Eli Zaretskii
  1 sibling, 1 reply; 48+ messages in thread
From: Chong Yidong @ 2012-05-10 14:13 UTC (permalink / raw)
  To: Dov Grobgeld; +Cc: 10580, schwab

Dov Grobgeld <dov.grobgeld@gmail.com> writes:

> Still, it bothering me the fact that the above perl expression parses
> the gdb output in a fraction of a second, (0.01s user time) whereas
> gdb-mi.el takes more than 40s.

I would also like to learn more about where the bottleneck is.

Could you do the following:

M-: (require 'gdb-mi) RET
M-: (defun gdb-get-source-file-list () nil) RET

then run M-x gdb as usual, and see if that makes any difference in
performance?  Leave gdb-create-source-file-list set at t.

(The above steps cause gdb-mi to issue the -file-list-exec-source-files
command and read the output, as usual, but skip parsing the output into
the source file list.)





^ permalink raw reply	[flat|nested] 48+ messages in thread

* bug#10580: 24.0.92; gdb initialization takes more than one minute at 100% CPU
  2012-05-10  6:00                                                           ` Dov Grobgeld
  2012-05-10 14:13                                                             ` Chong Yidong
@ 2012-05-10 16:32                                                             ` Eli Zaretskii
  2012-05-10 18:43                                                               ` Dov Grobgeld
  1 sibling, 1 reply; 48+ messages in thread
From: Eli Zaretskii @ 2012-05-10 16:32 UTC (permalink / raw)
  To: Dov Grobgeld; +Cc: cyd, schwab, 10580

> Date: Thu, 10 May 2012 09:00:49 +0300
> From: Dov Grobgeld <dov.grobgeld@gmail.com>
> Cc: schwab@linux-m68k.org, cyd@gnu.org, 10580@debbugs.gnu.org
> 
> I tried running file-list-exec-source-files and I get duplicates as well.
> Try the following:
> 
> prompt> echo -file-list-exec-source-files > /tmp/gdb.in
> prompt> gdb -i=mi emacs < /tmp/gdb.in > /tmp/gdb.out
> prompt> perl -ne 'while(/(\w+)=\"(.*?)\"/g) { print "$1=$2\n"; }'
> /tmp/gdb.out | sort | head -15
> file=alloc.c
> file=alloc.c
> file=allocator.c
> file=atimer.c
> file=atimer.c
> file=bidi.c
> file=bidi.c
> file=buffer.c
> file=buffer.c
> file=buffer.h
> file=buffer.h
> file=buffer.h
> file=buffer.h
> file=buffer.h
> file=buffer.h

I don't see anything like that.  Here's my output:

  addr=0x011b4ea5
  addr=0x011b4ea5
  addr=0x012329a8
  disp=del
  disp=del
  disp=keep
  enabled=y
  enabled=y
  enabled=y
  file=../lib/allocator.h
  file=../lib/careadlinkat.h
  file=../lib/ignore-value.h
  file=../lib/intprops.h
  file=../lib/intprops.h
  file=../lib/intprops.h

IOW, all the duplicates I see are header files.  Not a single .c file
shows up, not even if I change "head -15" into "head -100".

> My version of gdb is:
> 
> GNU gdb (GDB) Fedora (7.2-52.fc14)

Maybe you should upgrade, I dunno.  I use 7.4.1, FWIW.

Or maybe GCC versions later than what I have do that.

> For my executable gdb outputs full paths as well as the fullname field,
> which expands the output considerably.

Here too, but that's expected (and necessary).





^ permalink raw reply	[flat|nested] 48+ messages in thread

* bug#10580: 24.0.92; gdb initialization takes more than one minute at 100% CPU
  2012-05-10 16:32                                                             ` Eli Zaretskii
@ 2012-05-10 18:43                                                               ` Dov Grobgeld
  0 siblings, 0 replies; 48+ messages in thread
From: Dov Grobgeld @ 2012-05-10 18:43 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: cyd, schwab, 10580

[-- Attachment #1: Type: text/plain, Size: 2911 bytes --]

I just downloaded gdb from cvs and tried with the latest version and there
are still duplicates. Perhaps it is because of gcc? But on the positive
side there is indeed a huge difference in the gdb output.

prompt> gdb --version
GNU gdb (GDB) Fedora (7.3.50.20110722-13.fc16)
prompt> /usr/local/public-dev/bin/gdb --version
GNU gdb (GDB) 7.4.50.20120509-cvs
prompt> gdb -i=mi MyExec < /tmp/gdb.in > /tmp/gdb-old.out
prompt> /usr/local/public-dev/bin/gdb -i=mi MyExec < /tmp/gdb.in >
/tmp/gdb-new.out
prompt> ls -1s --block-size=1 /tmp/gdb*.out
 884736 /tmp/gdb-new.out
3727360 /tmp/gdb-old.out
prompt> perl -ne 'while(/(\w+)=\"(.*?)\"/g) { print "$1=$2\n"; }'
/tmp/gdb-old.out | sort | wc
  67311   67311 3522494
prompt> perl -ne 'while(/(\w+)=\"(.*?)\"/g) { print "$1=$2\n"; }'
/tmp/gdb-new.out | sort | wc
  14221   14221  837082
prompt> perl -ne 'while(/(\w+)=\"(.*?)\"/g) { print "$1=$2\n"; }'
/tmp/gdb-old.out | sort |uniq| wc
   3931    3931  220654
prompt> perl -ne 'while(/(\w+)=\"(.*?)\"/g) { print "$1=$2\n"; }'
/tmp/gdb-new.out | sort |uniq| wc
   2245    2245  137404

But even the factor 837k vs 137k is substantial, so it is still valid to do
an internal uniq within gdb. I'll try to put together a patch.

Regards,
Dov

On Thu, May 10, 2012 at 7:32 PM, Eli Zaretskii <eliz@gnu.org> wrote:

> > Date: Thu, 10 May 2012 09:00:49 +0300
> > From: Dov Grobgeld <dov.grobgeld@gmail.com>
> > Cc: schwab@linux-m68k.org, cyd@gnu.org, 10580@debbugs.gnu.org
> >
> > I tried running file-list-exec-source-files and I get duplicates as well.
> > Try the following:
> >
> > prompt> echo -file-list-exec-source-files > /tmp/gdb.in
> > prompt> gdb -i=mi emacs < /tmp/gdb.in > /tmp/gdb.out
> > prompt> perl -ne 'while(/(\w+)=\"(.*?)\"/g) { print "$1=$2\n"; }'
> > /tmp/gdb.out | sort | head -15
> > file=alloc.c
> > file=alloc.c
> > file=allocator.c
> > file=atimer.c
> > file=atimer.c
> > file=bidi.c
> > file=bidi.c
> > file=buffer.c
> > file=buffer.c
> > file=buffer.h
> > file=buffer.h
> > file=buffer.h
> > file=buffer.h
> > file=buffer.h
> > file=buffer.h
>
> I don't see anything like that.  Here's my output:
>
>  addr=0x011b4ea5
>  addr=0x011b4ea5
>  addr=0x012329a8
>  disp=del
>  disp=del
>  disp=keep
>  enabled=y
>  enabled=y
>  enabled=y
>  file=../lib/allocator.h
>  file=../lib/careadlinkat.h
>  file=../lib/ignore-value.h
>  file=../lib/intprops.h
>  file=../lib/intprops.h
>  file=../lib/intprops.h
>
> IOW, all the duplicates I see are header files.  Not a single .c file
> shows up, not even if I change "head -15" into "head -100".
>
> > My version of gdb is:
> >
> > GNU gdb (GDB) Fedora (7.2-52.fc14)
>
> Maybe you should upgrade, I dunno.  I use 7.4.1, FWIW.
>
> Or maybe GCC versions later than what I have do that.
>
> > For my executable gdb outputs full paths as well as the fullname field,
> > which expands the output considerably.
>
> Here too, but that's expected (and necessary).
>

[-- Attachment #2: Type: text/html, Size: 4287 bytes --]

^ permalink raw reply	[flat|nested] 48+ messages in thread

* bug#10580: 24.0.92; gdb initialization takes more than one minute at 100% CPU
  2012-05-10 14:13                                                             ` Chong Yidong
@ 2012-05-10 19:07                                                               ` Dov Grobgeld
  2012-05-10 20:25                                                                 ` Stefan Monnier
  2012-05-11  6:33                                                                 ` Chong Yidong
  0 siblings, 2 replies; 48+ messages in thread
From: Dov Grobgeld @ 2012-05-10 19:07 UTC (permalink / raw)
  To: Chong Yidong; +Cc: 10580, schwab

[-- Attachment #1: Type: text/plain, Size: 1143 bytes --]

Here are the tests when using the the latest cvs gdb that yields a gdb
output file of about 800k.

Without gdb-get-source-file-list override: ~139s
With gdb-get-source-file-list override: ~125s

Thus it is clear that most of the time is taken just reading the string
into emacs. But doing find-file on the same file is almost instantaneous.

Regards,
Dov


On Thu, May 10, 2012 at 5:13 PM, Chong Yidong <cyd@gnu.org> wrote:

> Dov Grobgeld <dov.grobgeld@gmail.com> writes:
>
> > Still, it bothering me the fact that the above perl expression parses
> > the gdb output in a fraction of a second, (0.01s user time) whereas
> > gdb-mi.el takes more than 40s.
>
> I would also like to learn more about where the bottleneck is.
>
> Could you do the following:
>
> M-: (require 'gdb-mi) RET
> M-: (defun gdb-get-source-file-list () nil) RET
>
> then run M-x gdb as usual, and see if that makes any difference in
> performance?  Leave gdb-create-source-file-list set at t.
>
> (The above steps cause gdb-mi to issue the -file-list-exec-source-files
> command and read the output, as usual, but skip parsing the output into
> the source file list.)
>

[-- Attachment #2: Type: text/html, Size: 1665 bytes --]

^ permalink raw reply	[flat|nested] 48+ messages in thread

* bug#10580: 24.0.92; gdb initialization takes more than one minute at 100% CPU
  2012-05-10 19:07                                                               ` Dov Grobgeld
@ 2012-05-10 20:25                                                                 ` Stefan Monnier
  2012-05-11  6:33                                                                 ` Chong Yidong
  1 sibling, 0 replies; 48+ messages in thread
From: Stefan Monnier @ 2012-05-10 20:25 UTC (permalink / raw)
  To: Dov Grobgeld; +Cc: tomo, Chong Yidong, schwab, 10580

> Here are the tests when using the the latest cvs gdb that yields a gdb
> output file of about 800k.

> Without gdb-get-source-file-list override: ~139s
> With gdb-get-source-file-list override: ~125s

> Thus it is clear that most of the time is taken just reading the string
> into emacs. But doing find-file on the same file is almost instantaneous.

Sounds like a perfect test case for the native elisp profiler (a
prototype of which is at
http://cx4a.org/hack/emacs-native-profiler.html, and hopefully it will
mature over the summer since it's funded as a GSoC).


        Stefan





^ permalink raw reply	[flat|nested] 48+ messages in thread

* bug#10580: 24.0.92; gdb initialization takes more than one minute at 100% CPU
  2012-05-10 19:07                                                               ` Dov Grobgeld
  2012-05-10 20:25                                                                 ` Stefan Monnier
@ 2012-05-11  6:33                                                                 ` Chong Yidong
  2012-05-11  8:29                                                                   ` Dov Grobgeld
  1 sibling, 1 reply; 48+ messages in thread
From: Chong Yidong @ 2012-05-11  6:33 UTC (permalink / raw)
  To: Dov Grobgeld; +Cc: 10580, schwab

[-- Attachment #1: Type: text/plain, Size: 646 bytes --]

Dov Grobgeld <dov.grobgeld@gmail.com> writes:

> Here are the tests when using the the latest cvs gdb that yields a gdb
> output file of about 800k.
>
> Without gdb-get-source-file-list override: ~139s
> With gdb-get-source-file-list override: ~125s
>
> Thus it is clear that most of the time is taken just reading the
> string into emacs. But doing find-file on the same file is almost
> instantaneous.

Here's another little experiment.  Could you apply the two attached
patches, individually, and see what difference each patch makes?
(Again, with gdb-create-source-file-list at its default of t, and
without any other patches to gdb-mi.el.)


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: gdb-test-1.patch --]
[-- Type: text/x-diff, Size: 3087 bytes --]

=== modified file 'lisp/progmodes/gdb-mi.el'
*** lisp/progmodes/gdb-mi.el	2012-04-20 10:09:40 +0000
--- lisp/progmodes/gdb-mi.el	2012-05-11 06:21:29 +0000
***************
*** 1918,1923 ****
--- 1918,1925 ----
      (gdb-ignored-notification . "=[-[:alpha:]]+,?\\(.*?\\)\n")
      (gdb-shell . "\\(\\(?:^.+\n\\)+\\)")))
  
+ (defvar gdb-accumulator nil)
+ 
  (defun gud-gdbmi-marker-filter (string)
    "Filter GDB/MI output."
  
***************
*** 1928,1954 ****
  	     (> (length gdb-debug-log) gdb-debug-log-max))
  	(setcdr (nthcdr (1- gdb-debug-log-max) gdb-debug-log) nil)))
  
!   ;; Recall the left over gud-marker-acc from last time
!   (setq gud-marker-acc (concat gud-marker-acc string))
  
    ;; Start accumulating output for the GUD buffer
    (setq gdb-filter-output "")
-   (let (output-record-list)
  
!     ;; Process all the complete markers in this chunk.
!     (dolist (gdbmi-record gdbmi-record-list)
!       (while (string-match (cdr gdbmi-record) gud-marker-acc)
! 	(push (list (match-beginning 0)
! 		    (car gdbmi-record)
! 		    (match-string 1 gud-marker-acc)
! 		    (match-string 2 gud-marker-acc)
! 		    (match-end 0))
! 	      output-record-list)
! 	(setq gud-marker-acc
! 	      (concat (substring gud-marker-acc 0 (match-beginning 0))
! 		      ;; Pad with spaces to preserve position.
! 		      (make-string (length (match-string 0 gud-marker-acc)) 32)
! 		      (substring gud-marker-acc (match-end 0))))))
  
      (setq output-record-list (sort output-record-list 'gdb-car<))
  
--- 1930,1960 ----
  	     (> (length gdb-debug-log) gdb-debug-log-max))
  	(setcdr (nthcdr (1- gdb-debug-log-max) gdb-debug-log) nil)))
  
!   ;; Recall the left over output from last time
!   (unless gdb-accumulator
!     (setq gdb-accumulator (get-buffer-create " *gdb output accumulator")))
! 
!   (with-current-buffer gdb-accumulator
!     (goto-char (point-max))
!     (insert string))
  
    ;; Start accumulating output for the GUD buffer
    (setq gdb-filter-output "")
  
!   ;; Process all the complete markers in this chunk.
!   (let (output-record-list marker)
!     (with-current-buffer gdb-accumulator
!       (dolist (gdbmi-record gdbmi-record-list)
! 	(goto-char (point-min))
! 	(while (re-search-forward (cdr gdbmi-record) nil t)
! 	  (setq marker (make-marker))
! 	  (set-marker marker (match-beginning 0))
! 	  (push (list marker
! 		      (car gdbmi-record)
! 		      (match-string 1)
! 		      (match-string 2))
! 		output-record-list)
! 	  (replace-match "\n"))))
  
      (setq output-record-list (sort output-record-list 'gdb-car<))
  
***************
*** 1969,1976 ****
  
      (setq gdb-output-sink 'user)
      ;; Remove padding.
!     (string-match "^ *" gud-marker-acc)
!     (setq gud-marker-acc (substring gud-marker-acc (match-end 0)))
  
      gdb-filter-output))
  
--- 1975,1984 ----
  
      (setq gdb-output-sink 'user)
      ;; Remove padding.
!     (with-current-buffer gdb-accumulator
!       (goto-char (point-min))
!       (while (re-search-forward "^\n" nil t)
!     	(replace-match "")))
  
      gdb-filter-output))
  


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #3: gdb-test-2.patch --]
[-- Type: text/x-diff, Size: 4485 bytes --]

=== modified file 'lisp/progmodes/gdb-mi.el'
*** lisp/progmodes/gdb-mi.el	2012-04-20 10:09:40 +0000
--- lisp/progmodes/gdb-mi.el	2012-05-11 06:32:52 +0000
***************
*** 1904,1923 ****
    (< (car a) (car b)))
  
  (defvar gdbmi-record-list
!   '((gdb-gdb . "(gdb) \n")
!     (gdb-done . "\\([0-9]*\\)\\^done,?\\(.*?\\)\n")
!     (gdb-starting . "\\([0-9]*\\)\\^running\n")
!     (gdb-error . "\\([0-9]*\\)\\^error,\\(.*?\\)\n")
!     (gdb-console . "~\\(\".*?\"\\)\n")
!     (gdb-internals . "&\\(\".*?\"\\)\n")
!     (gdb-stopped . "\\*stopped,?\\(.*?\\)\n")
!     (gdb-running . "\\*running,\\(.*?\n\\)")
!     (gdb-thread-created . "=thread-created,\\(.*?\n\\)")
!     (gdb-thread-selected . "=thread-selected,\\(.*?\\)\n")
!     (gdb-thread-exited . "=thread-exited,\\(.*?\n\\)")
!     (gdb-ignored-notification . "=[-[:alpha:]]+,?\\(.*?\\)\n")
      (gdb-shell . "\\(\\(?:^.+\n\\)+\\)")))
  
  (defun gud-gdbmi-marker-filter (string)
    "Filter GDB/MI output."
  
--- 1904,1925 ----
    (< (car a) (car b)))
  
  (defvar gdbmi-record-list
!   '((gdb-gdb . "^(gdb) \n")
!     (gdb-done . "^\\([0-9]*\\)\\^done,?\\(.*?\\)\n")
!     (gdb-starting . "^\\([0-9]*\\)\\^running\n")
!     (gdb-error . "^\\([0-9]*\\)\\^error,\\(.*?\\)\n")
!     (gdb-console . "^~\\(\".*?\"\\)\n")
!     (gdb-internals . "^&\\(\".*?\"\\)\n")
!     (gdb-stopped . "^\\*stopped,?\\(.*?\\)\n")
!     (gdb-running . "^\\*running,\\(.*?\n\\)")
!     (gdb-thread-created . "^=thread-created,\\(.*?\n\\)")
!     (gdb-thread-selected . "^=thread-selected,\\(.*?\\)\n")
!     (gdb-thread-exited . "^=thread-exited,\\(.*?\n\\)")
!     (gdb-ignored-notification . "^=[-[:alpha:]]+,?\\(.*?\\)\n")
      (gdb-shell . "\\(\\(?:^.+\n\\)+\\)")))
  
+ (defvar gdb-accumulator nil)
+ 
  (defun gud-gdbmi-marker-filter (string)
    "Filter GDB/MI output."
  
***************
*** 1928,1954 ****
  	     (> (length gdb-debug-log) gdb-debug-log-max))
  	(setcdr (nthcdr (1- gdb-debug-log-max) gdb-debug-log) nil)))
  
!   ;; Recall the left over gud-marker-acc from last time
!   (setq gud-marker-acc (concat gud-marker-acc string))
  
    ;; Start accumulating output for the GUD buffer
    (setq gdb-filter-output "")
-   (let (output-record-list)
  
!     ;; Process all the complete markers in this chunk.
!     (dolist (gdbmi-record gdbmi-record-list)
!       (while (string-match (cdr gdbmi-record) gud-marker-acc)
! 	(push (list (match-beginning 0)
! 		    (car gdbmi-record)
! 		    (match-string 1 gud-marker-acc)
! 		    (match-string 2 gud-marker-acc)
! 		    (match-end 0))
! 	      output-record-list)
! 	(setq gud-marker-acc
! 	      (concat (substring gud-marker-acc 0 (match-beginning 0))
! 		      ;; Pad with spaces to preserve position.
! 		      (make-string (length (match-string 0 gud-marker-acc)) 32)
! 		      (substring gud-marker-acc (match-end 0))))))
  
      (setq output-record-list (sort output-record-list 'gdb-car<))
  
--- 1930,1960 ----
  	     (> (length gdb-debug-log) gdb-debug-log-max))
  	(setcdr (nthcdr (1- gdb-debug-log-max) gdb-debug-log) nil)))
  
!   ;; Recall the left over output from last time
!   (unless gdb-accumulator
!     (setq gdb-accumulator (get-buffer-create " *gdb output accumulator")))
! 
!   (with-current-buffer gdb-accumulator
!     (goto-char (point-max))
!     (insert string))
  
    ;; Start accumulating output for the GUD buffer
    (setq gdb-filter-output "")
  
!   ;; Process all the complete markers in this chunk.
!   (let (output-record-list marker)
!     (with-current-buffer gdb-accumulator
!       (dolist (gdbmi-record gdbmi-record-list)
! 	(goto-char (point-min))
! 	(while (re-search-forward (cdr gdbmi-record) nil t)
! 	  (setq marker (make-marker))
! 	  (set-marker marker (match-beginning 0))
! 	  (push (list marker
! 		      (car gdbmi-record)
! 		      (match-string 1)
! 		      (match-string 2))
! 		output-record-list)
! 	  (replace-match "\n"))))
  
      (setq output-record-list (sort output-record-list 'gdb-car<))
  
***************
*** 1969,1976 ****
  
      (setq gdb-output-sink 'user)
      ;; Remove padding.
!     (string-match "^ *" gud-marker-acc)
!     (setq gud-marker-acc (substring gud-marker-acc (match-end 0)))
  
      gdb-filter-output))
  
--- 1975,1984 ----
  
      (setq gdb-output-sink 'user)
      ;; Remove padding.
!     (with-current-buffer gdb-accumulator
!       (goto-char (point-min))
!       (while (re-search-forward "^\n" nil t)
!     	(replace-match "")))
  
      gdb-filter-output))
  


^ permalink raw reply	[flat|nested] 48+ messages in thread

* bug#10580: 24.0.92; gdb initialization takes more than one minute at 100% CPU
  2012-05-11  6:33                                                                 ` Chong Yidong
@ 2012-05-11  8:29                                                                   ` Dov Grobgeld
  2012-05-11  9:47                                                                     ` Eli Zaretskii
  0 siblings, 1 reply; 48+ messages in thread
From: Dov Grobgeld @ 2012-05-11  8:29 UTC (permalink / raw)
  To: Chong Yidong; +Cc: 10580, schwab

[-- Attachment #1: Type: text/plain, Size: 972 bytes --]

Here are the results.

With patch1: ~155s
With patch2: ~112s

On the other hand, I have patched gdb, seehttp://
sourceware.org/bugzilla/show_bug.cgi?id=14081,  to do uniq internally in
gdb, and then it takes only about 10s.

On Fri, May 11, 2012 at 9:33 AM, Chong Yidong <cyd@gnu.org> wrote:

> Dov Grobgeld <dov.grobgeld@gmail.com> writes:
>
> > Here are the tests when using the the latest cvs gdb that yields a gdb
> > output file of about 800k.
> >
> > Without gdb-get-source-file-list override: ~139s
> > With gdb-get-source-file-list override: ~125s
> >
> > Thus it is clear that most of the time is taken just reading the
> > string into emacs. But doing find-file on the same file is almost
> > instantaneous.
>
> Here's another little experiment.  Could you apply the two attached
> patches, individually, and see what difference each patch makes?
> (Again, with gdb-create-source-file-list at its default of t, and
> without any other patches to gdb-mi.el.)
>
>

[-- Attachment #2: Type: text/html, Size: 1558 bytes --]

^ permalink raw reply	[flat|nested] 48+ messages in thread

* bug#10580: 24.0.92; gdb initialization takes more than one minute at 100% CPU
  2012-05-11  8:29                                                                   ` Dov Grobgeld
@ 2012-05-11  9:47                                                                     ` Eli Zaretskii
  2012-05-11 13:27                                                                       ` Chong Yidong
  0 siblings, 1 reply; 48+ messages in thread
From: Eli Zaretskii @ 2012-05-11  9:47 UTC (permalink / raw)
  To: Dov Grobgeld; +Cc: cyd, schwab, 10580

> Date: Fri, 11 May 2012 11:29:57 +0300
> From: Dov Grobgeld <dov.grobgeld@gmail.com>
> Cc: Eli Zaretskii <eliz@gnu.org>, schwab@linux-m68k.org, 10580@debbugs.gnu.org
> 
> With patch1: ~155s
> With patch2: ~112s
> 
> On the other hand, I have patched gdb, seehttp://
> sourceware.org/bugzilla/show_bug.cgi?id=14081,  to do uniq internally in
> gdb, and then it takes only about 10s.

Which is much faster, but still way too slow.

I think it's quite clear at this point that what takes time is reading
the stuff from GDB, not parsing it.  Chong, am I right?





^ permalink raw reply	[flat|nested] 48+ messages in thread

* bug#10580: 24.0.92; gdb initialization takes more than one minute at 100% CPU
  2012-05-11  9:47                                                                     ` Eli Zaretskii
@ 2012-05-11 13:27                                                                       ` Chong Yidong
  2012-11-05 20:36                                                                         ` Dov Grobgeld
  0 siblings, 1 reply; 48+ messages in thread
From: Chong Yidong @ 2012-05-11 13:27 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: Dov Grobgeld, 10580, schwab

Eli Zaretskii <eliz@gnu.org> writes:

> I think it's quite clear at this point that what takes time is reading
> the stuff from GDB, not parsing it.  Chong, am I right?

That is what the evidence suggests, which indicates that we won't be
able to fix it for 24.1.  Maybe there is some problem in the adaptive
read buffering code?





^ permalink raw reply	[flat|nested] 48+ messages in thread

* bug#10580: 24.0.92; gdb initialization takes more than one minute at 100% CPU
  2012-05-11 13:27                                                                       ` Chong Yidong
@ 2012-11-05 20:36                                                                         ` Dov Grobgeld
  2012-11-05 20:46                                                                           ` Eli Zaretskii
  0 siblings, 1 reply; 48+ messages in thread
From: Dov Grobgeld @ 2012-11-05 20:36 UTC (permalink / raw)
  To: Chong Yidong; +Cc: 10580, Andreas Schwab

[-- Attachment #1: Type: text/plain, Size: 633 bytes --]

Is there any chance of having this bug solved in the foreseeable future?
This bug is the reason I am still sticking with emacs-23. As an
alternative, is it possible to use the old gdb-mode (without -mi) in
emacs-24?



On Fri, May 11, 2012 at 4:27 PM, Chong Yidong <cyd@gnu.org> wrote:

> Eli Zaretskii <eliz@gnu.org> writes:
>
> > I think it's quite clear at this point that what takes time is reading
> > the stuff from GDB, not parsing it.  Chong, am I right?
>
> That is what the evidence suggests, which indicates that we won't be
> able to fix it for 24.1.  Maybe there is some problem in the adaptive
> read buffering code?
>

[-- Attachment #2: Type: text/html, Size: 1082 bytes --]

^ permalink raw reply	[flat|nested] 48+ messages in thread

* bug#10580: 24.0.92; gdb initialization takes more than one minute at 100% CPU
  2012-11-05 20:36                                                                         ` Dov Grobgeld
@ 2012-11-05 20:46                                                                           ` Eli Zaretskii
  2012-11-05 23:51                                                                             ` Stefan Monnier
  0 siblings, 1 reply; 48+ messages in thread
From: Eli Zaretskii @ 2012-11-05 20:46 UTC (permalink / raw)
  To: Dov Grobgeld; +Cc: cyd, schwab, 10580

> Date: Mon, 5 Nov 2012 22:36:16 +0200
> From: Dov Grobgeld <dov.grobgeld@gmail.com>
> Cc: Eli Zaretskii <eliz@gnu.org>, Andreas Schwab <schwab@linux-m68k.org>, 10580@debbugs.gnu.org
> 
> As an alternative, is it possible to use the old gdb-mode (without
> -mi) in emacs-24?

It was always possible: type "M-x gud-gdb RET".





^ permalink raw reply	[flat|nested] 48+ messages in thread

* bug#10580: 24.0.92; gdb initialization takes more than one minute at 100% CPU
  2012-11-05 20:46                                                                           ` Eli Zaretskii
@ 2012-11-05 23:51                                                                             ` Stefan Monnier
  0 siblings, 0 replies; 48+ messages in thread
From: Stefan Monnier @ 2012-11-05 23:51 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: Dov Grobgeld, cyd, schwab, 10580

>> As an alternative, is it possible to use the old gdb-mode (without
>> -mi) in emacs-24?
> It was always possible: type "M-x gud-gdb RET".

IIUC this gives you the Emacs-22 version of M-x gdb, but not the
Emacs-23 one (which used the gdb-ui.el code).


        Stefan





^ permalink raw reply	[flat|nested] 48+ messages in thread

* bug#10580: 24.0.92; gdb initialization takes more than one minute at 100
  2012-01-22 12:42 bug#10580: 24.0.92; gdb initialization takes more than one minute at 100% CPU Dov Grobgeld
  2012-01-23  0:53 ` Glenn Morris
@ 2012-12-14  4:14 ` Jean-Philippe Gravel
  2012-12-18  4:45   ` Jean-Philippe Gravel
  1 sibling, 1 reply; 48+ messages in thread
From: Jean-Philippe Gravel @ 2012-12-14  4:14 UTC (permalink / raw)
  To: 10580

[-- Attachment #1: Type: text/plain, Size: 2441 bytes --]

Hi guys,



I actually have a fix for this problem.



I use Emacs to debug a software of colossal size.  With Emacs 23, it used
to be possible to start gdb within a minute.  With Emacs 24, it takes more
than a couple of hour.  I never actually had the patience to wait for it to
finish.



As stated in previous posts, the command -file-list-exec-source-files is
the one triggering the bottleneck.  In my case, the reply is 5Mb long.



It turns out that the problem IS the parsing of the data stream coming from
GDB.  The function gud-gdbmi-marker-filter is home to a colossal
bottleneck.  You’ll find in there not only one, but 4 major algorithmic
problems.



The first thing that strikes the eye is the way it handles the fact that
there are several types of GDB replies possible.  Instead of parsing the
data stream linearly, accepting the GDB messages in the order of arrival,
it looks over the whole stream for the first type of message, then the
second, then the next.  Complexity: O(nm), where n is the size of the steam
and m is the number of message types.  Then, when finding a message
matching the type we look for, it is removed from the stream by cloning the
whole string, but padding the original location with spaces.  Complexity:
O(ni), where i is the number of messages.



To go on with the analysis, consider the following: my tests indicate that
gdbmi-marker-filter receives data by chunk of about 225 bytes.  Since I
receive 5Mb of data, gdbmi ingests about 22000 packets.  For every chunk of
data received, the incoming data is concatenated to a new string: O(nj),
where j is the number of packets.  Each time, the whole parsing described
above is restarted: O(nmj) (!!!).  Feed in a 5Mb data stream and you’ll get
a hung emacs!



I fixed the above by writing a proper parser reading the data stream in
O(n).  With my test-case, the parse time goes down from ‘too long to even
tell’, to about 3 seconds.  Not only does it fix the startup problem, but
it makes pretty much all other gud commands impressively faster.  With
emacs 23, it used to take almost a full second to do a single “gud-next” in
my software.  When enabling gud-tooltip-mode, it was becoming totally
unusable.  By removing the bottleneck in gud-gdbmi-marker-filter, the above
become instantaneous.



I just need to finalize a few things and I can send you a patch file.



Cheers!

[-- Attachment #2: Type: text/html, Size: 4847 bytes --]

^ permalink raw reply	[flat|nested] 48+ messages in thread

* bug#10580: 24.0.92; gdb initialization takes more than one minute at 100
  2012-12-14  4:14 ` bug#10580: 24.0.92; gdb initialization takes more than one minute at 100 Jean-Philippe Gravel
@ 2012-12-18  4:45   ` Jean-Philippe Gravel
  2012-12-21  4:01     ` Chong Yidong
  0 siblings, 1 reply; 48+ messages in thread
From: Jean-Philippe Gravel @ 2012-12-18  4:45 UTC (permalink / raw)
  To: 10580

[-- Attachment #1: Type: text/plain, Size: 3122 bytes --]

Here is my patch.

As stated previously, I only re-wrote gud-gdbmi-marker-filter.  This
function now parses the GDB/MI records in the order of arrival.  Only
the signature of each record is read by the new parser.  The actual
content of the record (i.e. result strings) is still parsed by the
original code (which I will refer to as the record handlers below).

The new parser is based on the GDB/MI output BNF grammar available at:
ftp://ftp.gnu.org/pub/old-gnu/Manuals/gdb/html_node/gdb_214.html#SEC221

Records that are too large to be received in one data chunk can be
parsed progressively by the record handlers, if they support it.  The
global configuration alist “gdbmi-bnf-result-state-configs” defines
the mapping between record types and record handlers.  This structure
flags all the handlers as either progressive or atomic.

Progressive handlers are invokes as soon as a partial data chunks are
received.  Atomic handlers on the other hand will not be invoked until
the whole record is received.  This design allowed me to progressively
attack the optimization problem: the ^done / ^error messages being the
biggest bottleneck (the reply to -file-list-exec-source-files), I
started by only converting those to progressive parsing.  If we find
that other messages cause performance issue, we can always convert
them to progressive parsing as well.

That being said, while the handler for ^done and ^error
(gdb-done-or-error) do receive the data progressively, it doesn’t
parse it on the fly.  Instead, it accumulates the data chunks in a
temporary buffer and parses its content only when the record is
complete.  This is sub-optimal, but my tests showed that optimizing
this part would have only a minimal effect compared to fixing
gud-gdbmi-marker-filter.  I decided to keep this as a separate
optimization task, to be done later.

For performance reason, I tried to keep processing and data copy to a
minimum.  I therefore work in-place, directly in the gud-marker-acc
string, instead of copying the string to a temporary buffer.  The
parser walks in the string using an offset stored in gdbmi-bnf-offset.
 By looking at the character at this offset, I can quickly detect the
type of record we received, BEFORE trying to parse it with
string-match.

Note: I am a little confused about when the parser states should be
(re)initialized.  I would have expected the states to be initialized
before the GDB process is started (before gud-common-init) because
once the process starts, the marker-filter can be invoked at any time.
 Instead, I find that the gdb-mi variables are all initialized in
gdb-init-1, which runs after the process is started.  I added a new
function gdbmi-bnf-init that is invoked from within gdb-init-1, but
that doesn’t seem right.  Does anyone have an opinion on this?  I
certainly do think there is currently a problem because if the GDB/MI
initialization is interrupted expectedly (for instance because of an
error), it seems to restart in a very bad state the next time (I think
that's true even before my fix)…

Jean-Philippe

[-- Attachment #2: gdb-mi-optimization-1.patch --]
[-- Type: application/octet-stream, Size: 23973 bytes --]

=== modified file 'lisp/progmodes/gdb-mi.el'
*** lisp/progmodes/gdb-mi.el	2012-10-18 19:46:18 +0000
--- lisp/progmodes/gdb-mi.el	2012-12-18 04:32:26 +0000
*************** Also display the main routine in the dis
*** 507,512 ****
--- 507,519 ----
    :group 'gdb
    :version "22.1")
  
+ (defcustom gdbmi-debug-mode nil
+   "When non-nil, all the messages sent or received from GDB/MI are printed in
+ the *Messages* buffer."
+   :type 'boolean
+   :group 'gud
+   :version "24.3")
+ 
  (defun gdb-force-mode-line-update (status)
    (let ((buffer gud-comint-buffer))
      (if (and buffer (buffer-name buffer))
*************** detailed description of this mode.
*** 846,851 ****
--- 853,860 ----
          gdb-register-names '()
          gdb-non-stop gdb-non-stop-setting)
    ;;
+   (gdbmi-bnf-init)
+   ;;
    (setq gdb-buffer-type 'gdbmi)
    ;;
    (gdb-force-mode-line-update
*************** complete."
*** 1739,1744 ****
--- 1748,1754 ----
    (setq gdb-token-number (1+ gdb-token-number))
    (setq command (concat (number-to-string gdb-token-number) command))
    (push (cons gdb-token-number handler-function) gdb-handler-alist)
+   (if gdbmi-debug-mode (message "gdb-input: %s" command))
    (process-send-string (get-buffer-process gud-comint-buffer)
  		       (concat command "\n")))
  
*************** is running."
*** 1874,1896 ****
        (set-window-buffer source-window buffer))
      source-window))
  
- (defun gdb-car< (a b)
-   (< (car a) (car b)))
  
! (defvar gdbmi-record-list
!   '((gdb-gdb . "(gdb) \n")
!     (gdb-done . "\\([0-9]*\\)\\^done,?\\(.*?\\)\n")
!     (gdb-starting . "\\([0-9]*\\)\\^running\n")
!     (gdb-error . "\\([0-9]*\\)\\^error,\\(.*?\\)\n")
!     (gdb-console . "~\\(\".*?\"\\)\n")
!     (gdb-internals . "&\\(\".*?\"\\)\n")
!     (gdb-stopped . "\\*stopped,?\\(.*?\\)\n")
!     (gdb-running . "\\*running,\\(.*?\n\\)")
!     (gdb-thread-created . "=thread-created,\\(.*?\n\\)")
!     (gdb-thread-selected . "=thread-selected,\\(.*?\\)\n")
!     (gdb-thread-exited . "=thread-exited,\\(.*?\n\\)")
!     (gdb-ignored-notification . "=[-[:alpha:]]+,?\\(.*?\\)\n")
!     (gdb-shell . "\\(\\(?:^.+\n\\)+\\)")))
  
  (defun gud-gdbmi-marker-filter (string)
    "Filter GDB/MI output."
--- 1884,2205 ----
        (set-window-buffer source-window buffer))
      source-window))
  
  
! (defun gdbmi-start-with (str offset match)
!   "Returns non-nil if string STR starts with MATCH, else returns nil.
! OFFSET is the position in STR at which the comparison takes place."
!   (let ((match-length (length match))
! 	(str-length (- (length str) offset)))
!     (when (>= str-length match-length)
!       (string-equal match (substring str offset (+ offset match-length))))))
! 
! (defun gdbmi-same-start (str offset match)
!   "Returns non-nil if STR and MATCH are equal up to the end of either strings, else returns nil.
! OFFSET is the position in STR at which the comparison takes place."
!   (let* ((str-length (- (length str) offset))
! 	 (match-length (length match))
! 	 (compare-length (min str-length match-length)))
!     (when (> compare-length 0)
!       (string-equal (substring str offset (+ offset compare-length))
! 		    (substring match 0 compare-length)))))
! 
! (defun gdbmi-is-number (character)
! "Returns non-nil if CHARACTER is a numerical character between 0 and 9,
! else returns nil."
!   (and (>= character ?0)
!        (<= character ?9)))
! 
! 
! (defvar gdbmi-bnf-state 'gdbmi-bnf-output
!   "Current GDB/MI output parser state.  The parser is placed in a
! different state when an incomplete data steam is received from GDB.
! This variable will preserve the state required to resume the parsing
! when more data arrives.")
! (make-variable-buffer-local 'gdbmi-bnf-state)
! 
! (defvar gdbmi-bnf-offset 0
!   "Offset in gud-marker-acc at which the parser is reading.
! This offset is used to be able to parse the GDB/MI message
! in-place, without the need of copying the string in a temporary buffer
! or discarding parsed tokens by substringing the message.")
! (make-variable-buffer-local 'gdbmi-bnf-offset)
! 
! (defun gdbmi-bnf-init ()
!   "Initializes the GDB/MI message parser"
!   (setq gdbmi-bnf-state 'gdbmi-bnf-output)
!   (setq gdbmi-bnf-offset 0)
!   (setq gud-marker-acc ""))
! 
! 
! (defun gdbmi-bnf-output ()
!   "Implementation of the following GDB/MI output grammar rule:
! 
!   output ==>
!        ( out-of-band-record )* [ result-record ] gdb-prompt"
! 
!     (gdbmi-bnf-skip-unrecognized)
!     (while (gdbmi-bnf-out-of-band-record))
!     (gdbmi-bnf-result-record)
!     (gdbmi-bnf-gdb-prompt))
! 
! 
! (defun gdbmi-bnf-skip-unrecognized ()
! "Used as a protection mechanism in case something goes wrong when parsing
! a GDB/MI reply message.  This function will skip characters until is encounters
! the beginning of a valid record."
!   (let ((acc-length (length gud-marker-acc))
! 	(prefix-offset gdbmi-bnf-offset)
! 	(prompt "(gdb) \n"))
! 
!     (while (and (< prefix-offset acc-length)
!                 (gdbmi-is-number (aref gud-marker-acc prefix-offset)))
!       (setq prefix-offset (1+ prefix-offset)))
! 
!     (if (and (< prefix-offset acc-length)
!              (not (member (aref gud-marker-acc prefix-offset) '(?^ ?* ?+ ?= ?~ ?@ ?&)))
!              (not (gdbmi-same-start gud-marker-acc gdbmi-bnf-offset prompt))
!              (string-match "\\([^^*+=~@&]+\\)" gud-marker-acc gdbmi-bnf-offset))
!         (let ((unrecognized-str (match-string 0 gud-marker-acc)))
!           (setq gdbmi-bnf-offset (match-end 0))
! 	  (if gdbmi-debug-mode (message "gdbmi-bnf-skip-unrecognized: %s" unrecognized-str))
!           (gdb-shell unrecognized-str)
! 	  t))))
! 
! 
! (defun gdbmi-bnf-gdb-prompt ()
!   "Implementation of the following GDB/MI output grammar rule:
!   gdb-prompt ==>
!        '(gdb)' nl
! 
!   nl ==>
!        CR | CR-LF"
! 
!   (let ((prompt "(gdb) \n"))
!     (when (gdbmi-start-with gud-marker-acc gdbmi-bnf-offset prompt)
!       (if gdbmi-debug-mode (message "gdbmi-bnf-gdb-prompt: %s" prompt))
!       (gdb-gdb prompt)
!       (setq gdbmi-bnf-offset (+ gdbmi-bnf-offset (length prompt)))
! 
!       ;; Returns non-nil to tell gud-gdbmi-marker-filter we've reached
!       ;; the end of a GDB reply message.
!       t)))
! 
! 
! (defun gdbmi-bnf-result-record ()
!   "Implementation of the following GDB/MI output grammar rule:
! 
!   result-record ==>
!        [ token ] '^' result-class ( ',' result )* nl
! 
!   token ==>
!        any sequence of digits."
! 
!   (gdbmi-bnf-result-and-async-record-impl))
! 
! 
! (defun gdbmi-bnf-out-of-band-record ()
!   "Implementation of the following GDB/MI output grammar rule:
! 
!   out-of-band-record ==>
!        async-record | stream-record"
! 
!   (or (gdbmi-bnf-async-record)
!       (gdbmi-bnf-stream-record)))
! 
! 
! (defun gdbmi-bnf-async-record ()
!   "Implementation of the following GDB/MI output grammar rules:
! 
!   async-record ==>
!        exec-async-output | status-async-output | notify-async-output
! 
!   exec-async-output ==>
!        [ token ] '*' async-output
! 
!   status-async-output ==>
!        [ token ] '+' async-output
! 
!   notify-async-output ==>
!        [ token ] '=' async-output
! 
!   async-output ==>
!        async-class ( ',' result )* nl"
! 
!   (gdbmi-bnf-result-and-async-record-impl))
! 
! 
! (defun gdbmi-bnf-stream-record ()
!   "Implement the following GDB/MI output grammar rule:
!   stream-record ==>
!        console-stream-output | target-stream-output | log-stream-output
! 
!   console-stream-output ==>
!        '~' c-string
! 
!   target-stream-output ==>
!        '@' c-string
! 
!   log-stream-output ==>
!        '&' c-string"
!   (when (< gdbmi-bnf-offset (length gud-marker-acc))
!     (if (and (member (aref gud-marker-acc gdbmi-bnf-offset) '(?~ ?@ ?&))
!              (string-match "\\([~@&]\\)\\(\".*?\"\\)\n" gud-marker-acc gdbmi-bnf-offset))
!         (let ((prefix (match-string 1 gud-marker-acc))
!               (c-string (match-string 2 gud-marker-acc)))
! 
!           (setq gdbmi-bnf-offset (match-end 0))
!           (if gdbmi-debug-mode (message "gdbmi-bnf-stream-record: %s" (match-string 0 gud-marker-acc)))
! 
!           (cond ((string-equal prefix "~")
!                  (gdbmi-bnf-console-stream-output c-string))
!                 ((string-equal prefix "@")
!                  (gdbmi-bnf-target-stream-output c-string))
!                 ((string-equal prefix "&")
!                  (gdbmi-bnf-log-stream-output c-string)))
! 	  t))))
! 
! (defun gdbmi-bnf-console-stream-output (c-string)
!   "Handler for the console-stream-output GDB/MI output grammar rule"
!   (gdb-console c-string))
! 
! (defun gdbmi-bnf-target-stream-output (c-string)
!   "Handler for the target-stream-output GDB/MI output grammar rule"
!   ;; Not currently used.
!   )
! 
! (defun gdbmi-bnf-log-stream-output (c-string)
!   "Handler for the log-stream-output GDB/MI output grammar rule"
!   ;; Suppress "No registers."  GDB 6.8 and earlier
!   ;; duplicates MI error message on internal stream.
!   ;; Don't print to GUD buffer.
!   (if (not (string-equal (read c-string) "No registers.\n"))
!       (gdb-internals c-string)))
! 
! 
! (defconst gdbmi-bnf-result-state-configs
!   '(("^" . (("done" . (gdb-done . progressive))
!             ("error" . (gdb-error . progressive))
!             ("running" . (gdb-starting . atomic))))
!     ("*" . (("stopped" . (gdb-stopped . atomic))
!             ("running" . (gdb-running . atomic))))
!     ("+" . ())
!     ("=" . (("thread-created" . (gdb-thread-created . atomic))
!             ("thread-selected" . (gdb-thread-selected . atomic))
!             ("thread-existed" . (gdb-ignored-notification . atomic))
!             ('default . (gdb-ignored-notification . atomic)))))
!   "Two dimensional alist, mapping the type and class of message to a handler function.
! Handler functions are all flagged as either 'progressive' or 'atomic'.  'progressive'
! handlers are capable of parsing incomplete messages.  They can be called several time
! with new data chunk as they arrive from GDB.  'progressive' handler must have an extra
! argument that is set to a non-nil value when the message is complete.
! 
! Implement the following GDB/MI output grammar rule:
!   result-class ==>
!        'done' | 'running' | 'connected' | 'error' | 'exit'
! 
!   async-class ==>
!        'stopped' | others (where others will be added depending on the needs--this is still in development).")
! 
! (defun gdbmi-bnf-result-and-async-record-impl ()
!   "Common implementation of the result-record and async-record rule.  Both rule share
! the same syntax.  Those records may be very large in size.  For that reason, the 'result'
! part of the  record is parsed by gdbmi-bnf-incomplete-record-result, which will keep
! receiving characters as they arrive from GDB until the record is complete."
!   (let ((acc-length (length gud-marker-acc))
! 	(prefix-offset gdbmi-bnf-offset))
! 
!     (while (and (< prefix-offset acc-length)
!                 (gdbmi-is-number (aref gud-marker-acc prefix-offset)))
!       (setq prefix-offset (1+ prefix-offset)))
! 
!     (if (and (< prefix-offset acc-length)
!              (member (aref gud-marker-acc prefix-offset) '(?* ?+ ?= ?^))
!              (string-match "\\([0-9]*\\)\\([*+=^]\\)\\(.+?\\)\\([,\n]\\)" gud-marker-acc gdbmi-bnf-offset))
! 
!         (let ((token (match-string 1 gud-marker-acc))
! 	      (prefix (match-string 2 gud-marker-acc))
! 	      (class (match-string 3 gud-marker-acc))
! 	      (complete (string-equal (match-string 4 gud-marker-acc) "\n"))
! 	      class-alist
! 	      class-command)
! 
!           (setq gdbmi-bnf-offset (match-end 0))
! 	  (if gdbmi-debug-mode (message "gdbmi-bnf-result-record: %s" (match-string 0 gud-marker-acc)))
! 
!           (setq class-alist (cdr (assoc prefix gdbmi-bnf-result-state-configs)))
!           (setq class-command (cdr (assoc class class-alist)))
!           (if (null class-command)
!               (setq class-command (cdr (assoc 'default class-alist))))
! 
!           (if complete
!               (if class-command
!                   (if (equal (cdr class-command) 'progressive)
!                       (funcall (car class-command) token "" complete)
!                     (funcall (car class-command) token "")))
!             (setq gdbmi-bnf-state `(lambda () (gdbmi-bnf-incomplete-record-result ,token ',class-command)))
!             (funcall gdbmi-bnf-state))
! 	  t))))
! 
! (defun gdbmi-bnf-incomplete-record-result (token class-command)
!   "State of the parser used to progressively parse a result-record or async-record
! rule from an incomplete data stream.  The parser will stay in this state until the end
! of the current result or async record is reached."
!   (when (< gdbmi-bnf-offset (length gud-marker-acc))
!     ;; Search the data stream for the end of the current record:
!     (if (string-match "\\([^\n]*\\)\\(\n?\\)" gud-marker-acc gdbmi-bnf-offset)
! 
!         (let ((result (match-string 1 gud-marker-acc))
!               (is-complete (string-equal (match-string 2 gud-marker-acc) "\n"))
!               (is-progressive (equal (cdr class-command) 'progressive)))
! 
!           ;; Update the gdbmi-bnf-offset only if the current chunk of data can
!           ;; be processed by the class-command handler:
!           (if (or is-complete is-progressive)
!               (setq gdbmi-bnf-offset (match-end 0)))
! 
! 	  (if gdbmi-debug-mode (message "gdbmi-bnf-incomplete-record-result: %s" (match-string 0 gud-marker-acc)))
! 
!           ;; Update the parsing state before invoking the handler in class-command
!           ;; to make sure it's not left in an invalid state if the handler was
!           ;; to generate an error.
!           (if is-complete
!               (setq gdbmi-bnf-state 'gdbmi-bnf-output))
! 
!           (if class-command
!               (if is-progressive
!                   (funcall (car class-command) token result is-complete)
!                 (if is-complete
!                     (funcall (car class-command) token result))))
! 
!           (unless is-complete ;; Incomplete gdb response: abort the parsing until we receive more data.
! 	    (if gdbmi-debug-mode (message "gdbmi-bnf-incomplete-record-result, aborting: incomplete stream"))
!             (throw 'gdbmi-incomplete-stream nil))
! 
!           is-complete))))
! 
! 
! ; The following grammar rules are not yet implemented by this GDBMI-BNF parser.
! ; The handling of those rules is currently done by the handlers registered
! ; in gdbmi-bnf-result-state-configs
! ;
! ; result ==>
! ;      variable "=" value
! ;
! ; variable ==>
! ;      string
! ;
! ; value ==>
! ;      const | tuple | list
! ;
! ; const ==>
! ;      c-string
! ;
! ; tuple ==>
! ;      "{}" | "{" result ( "," result )* "}"
! ;
! ; list ==>
! ;      "[]" | "[" value ( "," value )* "]" | "[" result ( "," result )* "]"
! 
  
  (defun gud-gdbmi-marker-filter (string)
    "Filter GDB/MI output."
*************** is running."
*** 1907,1952 ****
  
    ;; Start accumulating output for the GUD buffer.
    (setq gdb-filter-output "")
-   (let (output-record-list)
  
!     ;; Process all the complete markers in this chunk.
!     (dolist (gdbmi-record gdbmi-record-list)
!       (while (string-match (cdr gdbmi-record) gud-marker-acc)
! 	(push (list (match-beginning 0)
! 		    (car gdbmi-record)
! 		    (match-string 1 gud-marker-acc)
! 		    (match-string 2 gud-marker-acc)
! 		    (match-end 0))
! 	      output-record-list)
! 	(setq gud-marker-acc
! 	      (concat (substring gud-marker-acc 0 (match-beginning 0))
! 		      ;; Pad with spaces to preserve position.
! 		      (make-string (length (match-string 0 gud-marker-acc)) 32)
! 		      (substring gud-marker-acc (match-end 0))))))
! 
!     (setq output-record-list (sort output-record-list 'gdb-car<))
! 
!     (dolist (output-record output-record-list)
!       (let ((record-type (cadr output-record))
! 	    (arg1 (nth 2 output-record))
! 	    (arg2 (nth 3 output-record)))
! 	(cond ((eq record-type 'gdb-error)
! 	       (gdb-done-or-error arg2 arg1 'error))
! 	      ((eq record-type 'gdb-done)
! 	       (gdb-done-or-error arg2 arg1 'done))
! 	      ;; Suppress "No registers."  GDB 6.8 and earlier
! 	      ;; duplicates MI error message on internal stream.
! 	      ;; Don't print to GUD buffer.
! 	      ((not (and (eq record-type 'gdb-internals)
! 			 (string-equal (read arg1) "No registers.\n")))
! 	       (funcall record-type arg1)))))
  
!     (setq gdb-output-sink 'user)
!     ;; Remove padding.
!     (string-match "^ *" gud-marker-acc)
!     (setq gud-marker-acc (substring gud-marker-acc (match-end 0)))
  
!     gdb-filter-output))
  
  (defun gdb-gdb (_output-field))
  
--- 2216,2234 ----
  
    ;; Start accumulating output for the GUD buffer.
    (setq gdb-filter-output "")
  
!   (let ((acc-length (length gud-marker-acc)))
!     (catch 'gdbmi-incomplete-stream
!       (while (and (< gdbmi-bnf-offset acc-length)
! 		  (funcall gdbmi-bnf-state)))))
  
!   (setq gud-marker-acc (substring gud-marker-acc gdbmi-bnf-offset))
!   (setq gdbmi-bnf-offset 0)
! 
!   (when (and gdbmi-debug-mode (> (length gud-marker-acc) 0))
!     (message "gud-gdbmi-marker-filter, unparsed string: %s" gud-marker-acc))
  
!   gdb-filter-output)
  
  (defun gdb-gdb (_output-field))
  
*************** is running."
*** 1954,1964 ****
    (setq gdb-filter-output
          (concat output-field gdb-filter-output)))
  
! (defun gdb-ignored-notification (_output-field))
  
  ;; gdb-invalidate-threads is defined to accept 'update-threads signal
! (defun gdb-thread-created (_output-field))
! (defun gdb-thread-exited (output-field)
    "Handle =thread-exited async record: unset `gdb-thread-number'
   if current thread exited and update threads list."
    (let* ((thread-id (bindat-get-field (gdb-json-string output-field) 'id)))
--- 2236,2246 ----
    (setq gdb-filter-output
          (concat output-field gdb-filter-output)))
  
! (defun gdb-ignored-notification (_token _output-field))
  
  ;; gdb-invalidate-threads is defined to accept 'update-threads signal
! (defun gdb-thread-created (_token _output-field))
! (defun gdb-thread-exited (_token output-field)
    "Handle =thread-exited async record: unset `gdb-thread-number'
   if current thread exited and update threads list."
    (let* ((thread-id (bindat-get-field (gdb-json-string output-field) 'id)))
*************** is running."
*** 1971,1977 ****
      (gdb-wait-for-pending
       (gdb-emit-signal gdb-buf-publisher 'update-threads))))
  
! (defun gdb-thread-selected (output-field)
    "Handler for =thread-selected MI output record.
  
  Sets `gdb-thread-number' to new id."
--- 2253,2259 ----
      (gdb-wait-for-pending
       (gdb-emit-signal gdb-buf-publisher 'update-threads))))
  
! (defun gdb-thread-selected (_token output-field)
    "Handler for =thread-selected MI output record.
  
  Sets `gdb-thread-number' to new id."
*************** Sets `gdb-thread-number' to new id."
*** 1988,1994 ****
      (gdb-wait-for-pending
       (gdb-update))))
  
! (defun gdb-running (output-field)
    (let* ((thread-id
            (bindat-get-field (gdb-json-string output-field) 'thread-id)))
      ;; We reset gdb-frame-number to nil if current thread has gone
--- 2270,2276 ----
      (gdb-wait-for-pending
       (gdb-update))))
  
! (defun gdb-running (_token output-field)
    (let* ((thread-id
            (bindat-get-field (gdb-json-string output-field) 'thread-id)))
      ;; We reset gdb-frame-number to nil if current thread has gone
*************** Sets `gdb-thread-number' to new id."
*** 2006,2012 ****
    (setq gdb-active-process t)
    (gdb-emit-signal gdb-buf-publisher 'update-threads))
  
! (defun gdb-starting (_output-field)
    ;; CLI commands don't emit ^running at the moment so use gdb-running too.
    (setq gdb-inferior-status "running")
    (gdb-force-mode-line-update
--- 2288,2294 ----
    (setq gdb-active-process t)
    (gdb-emit-signal gdb-buf-publisher 'update-threads))
  
! (defun gdb-starting (_output-field result)
    ;; CLI commands don't emit ^running at the moment so use gdb-running too.
    (setq gdb-inferior-status "running")
    (gdb-force-mode-line-update
*************** Sets `gdb-thread-number' to new id."
*** 2020,2026 ****
  
  ;; -break-insert -t didn't give a reason before gdb 6.9
  
! (defun gdb-stopped (output-field)
    "Given the contents of *stopped MI async record, select new
  current thread and update GDB buffers."
    ;; Reason is available with target-async only
--- 2302,2308 ----
  
  ;; -break-insert -t didn't give a reason before gdb 6.9
  
! (defun gdb-stopped (_token output-field)
    "Given the contents of *stopped MI async record, select new
  current thread and update GDB buffers."
    ;; Reason is available with target-async only
*************** current thread and update GDB buffers."
*** 2106,2112 ****
    (setq gdb-filter-output
  	(gdb-concat-output gdb-filter-output (read output-field))))
  
! (defun gdb-done-or-error (output-field token-number type)
    (if (string-equal token-number "")
        ;; Output from command entered by user
        (progn
--- 2388,2400 ----
    (setq gdb-filter-output
  	(gdb-concat-output gdb-filter-output (read output-field))))
  
! (defun gdb-done (token-number output-field is-complete)
!   (gdb-done-or-error token-number 'done output-field is-complete))
! 
! (defun gdb-error (token-number output-field is-complete)
!   (gdb-done-or-error token-number 'error output-field is-complete))
! 
! (defun gdb-done-or-error (token-number type output-field is-complete)
    (if (string-equal token-number "")
        ;; Output from command entered by user
        (progn
*************** current thread and update GDB buffers."
*** 2122,2135 ****
      ;; Output from command from frontend.
      (setq gdb-output-sink 'emacs))
  
-   (gdb-clear-partial-output)
- 
    ;; The process may already be dead (e.g. C-d at the gdb prompt).
    (let* ((proc (get-buffer-process gud-comint-buffer))
  	 (no-proc (or (null proc)
  		      (memq (process-status proc) '(exit signal)))))
  
!     (when gdb-first-done-or-error
        (unless (or token-number gud-running no-proc)
  	(setq gdb-filter-output (concat gdb-filter-output gdb-prompt-name)))
        (gdb-update no-proc)
--- 2410,2421 ----
      ;; Output from command from frontend.
      (setq gdb-output-sink 'emacs))
  
    ;; The process may already be dead (e.g. C-d at the gdb prompt).
    (let* ((proc (get-buffer-process gud-comint-buffer))
  	 (no-proc (or (null proc)
  		      (memq (process-status proc) '(exit signal)))))
  
!     (when (and is-complete gdb-first-done-or-error)
        (unless (or token-number gud-running no-proc)
  	(setq gdb-filter-output (concat gdb-filter-output gdb-prompt-name)))
        (gdb-update no-proc)
*************** current thread and update GDB buffers."
*** 2138,2150 ****
      (setq gdb-filter-output
  	  (gdb-concat-output gdb-filter-output output-field))
  
!     (when token-number
        (with-current-buffer
  	  (gdb-get-buffer-create 'gdb-partial-output-buffer)
  	(funcall
  	 (cdr (assoc (string-to-number token-number) gdb-handler-alist))))
        (setq gdb-handler-alist
! 	    (assq-delete-all token-number gdb-handler-alist)))))
  
  (defun gdb-concat-output (so-far new)
    (cond
--- 2424,2442 ----
      (setq gdb-filter-output
  	  (gdb-concat-output gdb-filter-output output-field))
  
!     ;; We are done concatenating to the output sink.  Restore it to user sink:
!     (setq gdb-output-sink 'user)
! 
!     (when (and token-number is-complete)
        (with-current-buffer
  	  (gdb-get-buffer-create 'gdb-partial-output-buffer)
  	(funcall
  	 (cdr (assoc (string-to-number token-number) gdb-handler-alist))))
        (setq gdb-handler-alist
!             (assq-delete-all token-number gdb-handler-alist)))
! 
!   (when is-complete
!     (gdb-clear-partial-output))))
  
  (defun gdb-concat-output (so-far new)
    (cond


^ permalink raw reply	[flat|nested] 48+ messages in thread

* bug#10580: 24.0.92; gdb initialization takes more than one minute at 100
  2012-12-18  4:45   ` Jean-Philippe Gravel
@ 2012-12-21  4:01     ` Chong Yidong
  2013-03-01  3:31       ` Jean-Philippe Gravel
  0 siblings, 1 reply; 48+ messages in thread
From: Chong Yidong @ 2012-12-21  4:01 UTC (permalink / raw)
  To: Jean-Philippe Gravel; +Cc: 10580

Jean-Philippe Gravel <jpgravel@gmail.com> writes:

> As stated previously, I only re-wrote gud-gdbmi-marker-filter.  This
> function now parses the GDB/MI records in the order of arrival.  Only
> the signature of each record is read by the new parser.  The actual
> content of the record (i.e. result strings) is still parsed by the
> original code (which I will refer to as the record handlers below).
>
> The new parser is based on the GDB/MI output BNF grammar available at:
> ftp://ftp.gnu.org/pub/old-gnu/Manuals/gdb/html_node/gdb_214.html#SEC221

Thanks.  This looks like a very good change indeed.  In order for us to
include it in Emacs, we need a copyright assignment; I hope you will be
willing to sign one.  I will contact you off-list about how to do this.





^ permalink raw reply	[flat|nested] 48+ messages in thread

* bug#10580: 24.0.92; gdb initialization takes more than one minute at 100
  2012-12-21  4:01     ` Chong Yidong
@ 2013-03-01  3:31       ` Jean-Philippe Gravel
  2013-03-11 17:14         ` Stefan Monnier
  0 siblings, 1 reply; 48+ messages in thread
From: Jean-Philippe Gravel @ 2013-03-01  3:31 UTC (permalink / raw)
  To: 10580; +Cc: Chong Yidong

[-- Attachment #1: Type: text/plain, Size: 606 bytes --]

> Thanks.  This looks like a very good change indeed.  In order for us to
> include it in Emacs, we need a copyright assignment; I hope you will be
> willing to sign one.  I will contact you off-list about how to do this.

My copyright assignment is finally complete.

While I was waiting for that, I found a problem with my patch.  If you
use the gdb command "finish" to exit from a function, gdb replies with
a dump of the returned value (even though gdb-mi will not show it).
My previous patch was failing with a regexp overflow if the return
value was too big.  This new patch will solve this problem.

[-- Attachment #2: gdb-mi-optimization-2.patch --]
[-- Type: application/octet-stream, Size: 23541 bytes --]

*** trunk/lisp/progmodes/gdb-mi.el	2013-01-25 23:12:00.065758257 -0500
--- trunk-dev/lisp/progmodes/gdb-mi.el	2013-02-28 21:29:15.634063677 -0500
***************
*** 507,512 ****
--- 507,519 ----
    :group 'gdb
    :version "22.1")
  
+ (defcustom gdbmi-debug-mode nil
+   "When non-nil, all the messages sent or received from GDB/MI are printed in
+ the *Messages* buffer."
+   :type 'boolean
+   :group 'gud
+   :version "24.3")
+ 
  (defun gdb-force-mode-line-update (status)
    (let ((buffer gud-comint-buffer))
      (if (and buffer (buffer-name buffer))
***************
*** 846,851 ****
--- 853,860 ----
          gdb-register-names '()
          gdb-non-stop gdb-non-stop-setting)
    ;;
+   (gdbmi-bnf-init)
+   ;;
    (setq gdb-buffer-type 'gdbmi)
    ;;
    (gdb-force-mode-line-update
***************
*** 1739,1744 ****
--- 1748,1754 ----
    (setq gdb-token-number (1+ gdb-token-number))
    (setq command (concat (number-to-string gdb-token-number) command))
    (push (cons gdb-token-number handler-function) gdb-handler-alist)
+   (if gdbmi-debug-mode (message "gdb-input: %s" command))
    (process-send-string (get-buffer-process gud-comint-buffer)
  		       (concat command "\n")))
  
***************
*** 1874,1896 ****
        (set-window-buffer source-window buffer))
      source-window))
  
- (defun gdb-car< (a b)
-   (< (car a) (car b)))
  
! (defvar gdbmi-record-list
!   '((gdb-gdb . "(gdb) \n")
!     (gdb-done . "\\([0-9]*\\)\\^done,?\\(.*?\\)\n")
!     (gdb-starting . "\\([0-9]*\\)\\^running\n")
!     (gdb-error . "\\([0-9]*\\)\\^error,\\(.*?\\)\n")
!     (gdb-console . "~\\(\".*?\"\\)\n")
!     (gdb-internals . "&\\(\".*?\"\\)\n")
!     (gdb-stopped . "\\*stopped,?\\(.*?\\)\n")
!     (gdb-running . "\\*running,\\(.*?\n\\)")
!     (gdb-thread-created . "=thread-created,\\(.*?\n\\)")
!     (gdb-thread-selected . "=thread-selected,\\(.*?\\)\n")
!     (gdb-thread-exited . "=thread-exited,\\(.*?\n\\)")
!     (gdb-ignored-notification . "=[-[:alpha:]]+,?\\(.*?\\)\n")
!     (gdb-shell . "\\(\\(?:^.+\n\\)+\\)")))
  
  (defun gud-gdbmi-marker-filter (string)
    "Filter GDB/MI output."
--- 1884,2205 ----
        (set-window-buffer source-window buffer))
      source-window))
  
  
! (defun gdbmi-start-with (str offset match)
!   "Returns non-nil if string STR starts with MATCH, else returns nil.
! OFFSET is the position in STR at which the comparison takes place."
!   (let ((match-length (length match))
! 	(str-length (- (length str) offset)))
!     (when (>= str-length match-length)
!       (string-equal match (substring str offset (+ offset match-length))))))
! 
! (defun gdbmi-same-start (str offset match)
!   "Returns non-nil if STR and MATCH are equal up to the end of either strings, else returns nil.
! OFFSET is the position in STR at which the comparison takes place."
!   (let* ((str-length (- (length str) offset))
! 	 (match-length (length match))
! 	 (compare-length (min str-length match-length)))
!     (when (> compare-length 0)
!       (string-equal (substring str offset (+ offset compare-length))
! 		    (substring match 0 compare-length)))))
! 
! (defun gdbmi-is-number (character)
! "Returns non-nil if CHARACTER is a numerical character between 0 and 9,
! else returns nil."
!   (and (>= character ?0)
!        (<= character ?9)))
! 
! 
! (defvar gdbmi-bnf-state 'gdbmi-bnf-output
!   "Current GDB/MI output parser state.  The parser is placed in a
! different state when an incomplete data steam is received from GDB.
! This variable will preserve the state required to resume the parsing
! when more data arrives.")
! (make-variable-buffer-local 'gdbmi-bnf-state)
! 
! (defvar gdbmi-bnf-offset 0
!   "Offset in gud-marker-acc at which the parser is reading.
! This offset is used to be able to parse the GDB/MI message
! in-place, without the need of copying the string in a temporary buffer
! or discarding parsed tokens by substringing the message.")
! (make-variable-buffer-local 'gdbmi-bnf-offset)
! 
! (defun gdbmi-bnf-init ()
!   "Initializes the GDB/MI message parser"
!   (setq gdbmi-bnf-state 'gdbmi-bnf-output)
!   (setq gdbmi-bnf-offset 0)
!   (setq gud-marker-acc ""))
! 
! 
! (defun gdbmi-bnf-output ()
!   "Implementation of the following GDB/MI output grammar rule:
! 
!   output ==>
!        ( out-of-band-record )* [ result-record ] gdb-prompt"
! 
!     (gdbmi-bnf-skip-unrecognized)
!     (while (gdbmi-bnf-out-of-band-record))
!     (gdbmi-bnf-result-record)
!     (gdbmi-bnf-gdb-prompt))
! 
! 
! (defun gdbmi-bnf-skip-unrecognized ()
! "Used as a protection mechanism in case something goes wrong when parsing
! a GDB/MI reply message.  This function will skip characters until is encounters
! the beginning of a valid record."
!   (let ((acc-length (length gud-marker-acc))
! 	(prefix-offset gdbmi-bnf-offset)
! 	(prompt "(gdb) \n"))
! 
!     (while (and (< prefix-offset acc-length)
!                 (gdbmi-is-number (aref gud-marker-acc prefix-offset)))
!       (setq prefix-offset (1+ prefix-offset)))
! 
!     (if (and (< prefix-offset acc-length)
!              (not (member (aref gud-marker-acc prefix-offset) '(?^ ?* ?+ ?= ?~ ?@ ?&)))
!              (not (gdbmi-same-start gud-marker-acc gdbmi-bnf-offset prompt))
!              (string-match "\\([^^*+=~@&]+\\)" gud-marker-acc gdbmi-bnf-offset))
!         (let ((unrecognized-str (match-string 0 gud-marker-acc)))
!           (setq gdbmi-bnf-offset (match-end 0))
! 	  (if gdbmi-debug-mode (message "gdbmi-bnf-skip-unrecognized: %s" unrecognized-str))
!           (gdb-shell unrecognized-str)
! 	  t))))
! 
! 
! (defun gdbmi-bnf-gdb-prompt ()
!   "Implementation of the following GDB/MI output grammar rule:
!   gdb-prompt ==>
!        '(gdb)' nl
! 
!   nl ==>
!        CR | CR-LF"
! 
!   (let ((prompt "(gdb) \n"))
!     (when (gdbmi-start-with gud-marker-acc gdbmi-bnf-offset prompt)
!       (if gdbmi-debug-mode (message "gdbmi-bnf-gdb-prompt: %s" prompt))
!       (gdb-gdb prompt)
!       (setq gdbmi-bnf-offset (+ gdbmi-bnf-offset (length prompt)))
! 
!       ;; Returns non-nil to tell gud-gdbmi-marker-filter we've reached
!       ;; the end of a GDB reply message.
!       t)))
! 
! 
! (defun gdbmi-bnf-result-record ()
!   "Implementation of the following GDB/MI output grammar rule:
! 
!   result-record ==>
!        [ token ] '^' result-class ( ',' result )* nl
! 
!   token ==>
!        any sequence of digits."
! 
!   (gdbmi-bnf-result-and-async-record-impl))
! 
! 
! (defun gdbmi-bnf-out-of-band-record ()
!   "Implementation of the following GDB/MI output grammar rule:
! 
!   out-of-band-record ==>
!        async-record | stream-record"
! 
!   (or (gdbmi-bnf-async-record)
!       (gdbmi-bnf-stream-record)))
! 
! 
! (defun gdbmi-bnf-async-record ()
!   "Implementation of the following GDB/MI output grammar rules:
! 
!   async-record ==>
!        exec-async-output | status-async-output | notify-async-output
! 
!   exec-async-output ==>
!        [ token ] '*' async-output
! 
!   status-async-output ==>
!        [ token ] '+' async-output
! 
!   notify-async-output ==>
!        [ token ] '=' async-output
! 
!   async-output ==>
!        async-class ( ',' result )* nl"
! 
!   (gdbmi-bnf-result-and-async-record-impl))
! 
! 
! (defun gdbmi-bnf-stream-record ()
!   "Implement the following GDB/MI output grammar rule:
!   stream-record ==>
!        console-stream-output | target-stream-output | log-stream-output
! 
!   console-stream-output ==>
!        '~' c-string
! 
!   target-stream-output ==>
!        '@' c-string
! 
!   log-stream-output ==>
!        '&' c-string"
!   (when (< gdbmi-bnf-offset (length gud-marker-acc))
!     (if (and (member (aref gud-marker-acc gdbmi-bnf-offset) '(?~ ?@ ?&))
!              (string-match "\\([~@&]\\)\\(\".*?\"\\)\n" gud-marker-acc gdbmi-bnf-offset))
!         (let ((prefix (match-string 1 gud-marker-acc))
!               (c-string (match-string 2 gud-marker-acc)))
! 
!           (setq gdbmi-bnf-offset (match-end 0))
!           (if gdbmi-debug-mode (message "gdbmi-bnf-stream-record: %s" (match-string 0 gud-marker-acc)))
! 
!           (cond ((string-equal prefix "~")
!                  (gdbmi-bnf-console-stream-output c-string))
!                 ((string-equal prefix "@")
!                  (gdbmi-bnf-target-stream-output c-string))
!                 ((string-equal prefix "&")
!                  (gdbmi-bnf-log-stream-output c-string)))
! 	  t))))
! 
! (defun gdbmi-bnf-console-stream-output (c-string)
!   "Handler for the console-stream-output GDB/MI output grammar rule"
!   (gdb-console c-string))
! 
! (defun gdbmi-bnf-target-stream-output (c-string)
!   "Handler for the target-stream-output GDB/MI output grammar rule"
!   ;; Not currently used.
!   )
! 
! (defun gdbmi-bnf-log-stream-output (c-string)
!   "Handler for the log-stream-output GDB/MI output grammar rule"
!   ;; Suppress "No registers."  GDB 6.8 and earlier
!   ;; duplicates MI error message on internal stream.
!   ;; Don't print to GUD buffer.
!   (if (not (string-equal (read c-string) "No registers.\n"))
!       (gdb-internals c-string)))
! 
! 
! (defconst gdbmi-bnf-result-state-configs
!   '(("^" . (("done" . (gdb-done . progressive))
!             ("error" . (gdb-error . progressive))
!             ("running" . (gdb-starting . atomic))))
!     ("*" . (("stopped" . (gdb-stopped . atomic))
!             ("running" . (gdb-running . atomic))))
!     ("+" . ())
!     ("=" . (("thread-created" . (gdb-thread-created . atomic))
!             ("thread-selected" . (gdb-thread-selected . atomic))
!             ("thread-existed" . (gdb-ignored-notification . atomic))
!             ('default . (gdb-ignored-notification . atomic)))))
!   "Two dimensional alist, mapping the type and class of message to a handler function.
! Handler functions are all flagged as either 'progressive' or 'atomic'.  'progressive'
! handlers are capable of parsing incomplete messages.  They can be called several time
! with new data chunk as they arrive from GDB.  'progressive' handler must have an extra
! argument that is set to a non-nil value when the message is complete.
! 
! Implement the following GDB/MI output grammar rule:
!   result-class ==>
!        'done' | 'running' | 'connected' | 'error' | 'exit'
! 
!   async-class ==>
!        'stopped' | others (where others will be added depending on the needs--this is still in development).")
! 
! (defun gdbmi-bnf-result-and-async-record-impl ()
!   "Common implementation of the result-record and async-record rule.  Both rule share
! the same syntax.  Those records may be very large in size.  For that reason, the 'result'
! part of the  record is parsed by gdbmi-bnf-incomplete-record-result, which will keep
! receiving characters as they arrive from GDB until the record is complete."
!   (let ((acc-length (length gud-marker-acc))
! 	(prefix-offset gdbmi-bnf-offset))
! 
!     (while (and (< prefix-offset acc-length)
!                 (gdbmi-is-number (aref gud-marker-acc prefix-offset)))
!       (setq prefix-offset (1+ prefix-offset)))
! 
!     (if (and (< prefix-offset acc-length)
!              (member (aref gud-marker-acc prefix-offset) '(?* ?+ ?= ?^))
!              (string-match "\\([0-9]*\\)\\([*+=^]\\)\\(.+?\\)\\([,\n]\\)" gud-marker-acc gdbmi-bnf-offset))
! 
!         (let ((token (match-string 1 gud-marker-acc))
! 	      (prefix (match-string 2 gud-marker-acc))
! 	      (class (match-string 3 gud-marker-acc))
! 	      (complete (string-equal (match-string 4 gud-marker-acc) "\n"))
! 	      class-alist
! 	      class-command)
! 
!           (setq gdbmi-bnf-offset (match-end 0))
! 	  (if gdbmi-debug-mode (message "gdbmi-bnf-result-record: %s" (match-string 0 gud-marker-acc)))
! 
!           (setq class-alist (cdr (assoc prefix gdbmi-bnf-result-state-configs)))
!           (setq class-command (cdr (assoc class class-alist)))
!           (if (null class-command)
!               (setq class-command (cdr (assoc 'default class-alist))))
! 
!           (if complete
!               (if class-command
!                   (if (equal (cdr class-command) 'progressive)
!                       (funcall (car class-command) token "" complete)
!                     (funcall (car class-command) token "")))
!             (setq gdbmi-bnf-state `(lambda () (gdbmi-bnf-incomplete-record-result ,token ',class-command)))
!             (funcall gdbmi-bnf-state))
! 	  t))))
! 
! (defun gdbmi-bnf-incomplete-record-result (token class-command)
!   "State of the parser used to progressively parse a result-record or async-record
! rule from an incomplete data stream.  The parser will stay in this state until the end
! of the current result or async record is reached."
!   (when (< gdbmi-bnf-offset (length gud-marker-acc))
!     ;; Search the data stream for the end of the current record:
!     (let* ((newline-pos (string-match "\n" gud-marker-acc gdbmi-bnf-offset))
! 	   (is-progressive (equal (cdr class-command) 'progressive))
! 	   (is-complete (not (null newline-pos)))
! 	   result-str)
! 
!       ;; Update the gdbmi-bnf-offset only if the current chunk of data can
!       ;; be processed by the class-command handler:
!       (when (or is-complete is-progressive)
! 	(setq result-str (substring gud-marker-acc gdbmi-bnf-offset newline-pos))
! 	(setq gdbmi-bnf-offset (+ 1 newline-pos)))
! 
!       (if gdbmi-debug-mode (message "gdbmi-bnf-incomplete-record-result: %s" (substring gud-marker-acc gdbmi-bnf-offset newline-pos)))
! 
!       ;; Update the parsing state before invoking the handler in class-command
!       ;; to make sure it's not left in an invalid state if the handler was
!       ;; to generate an error.
!       (if is-complete
! 	  (setq gdbmi-bnf-state 'gdbmi-bnf-output))
! 
!       (if class-command
! 	  (if is-progressive
! 	      (funcall (car class-command) token result-str is-complete)
! 	    (if is-complete
! 		(funcall (car class-command) token result-str))))
! 
!       (unless is-complete ;; Incomplete gdb response: abort the parsing until we receive more data.
!         (if gdbmi-debug-mode (message "gdbmi-bnf-incomplete-record-result, aborting: incomplete stream"))
!         (throw 'gdbmi-incomplete-stream nil))
! 
!       is-complete)))
! 
! 
! ; The following grammar rules are not yet implemented by this GDBMI-BNF parser.
! ; The handling of those rules is currently done by the handlers registered
! ; in gdbmi-bnf-result-state-configs
! ;
! ; result ==>
! ;      variable "=" value
! ;
! ; variable ==>
! ;      string
! ;
! ; value ==>
! ;      const | tuple | list
! ;
! ; const ==>
! ;      c-string
! ;
! ; tuple ==>
! ;      "{}" | "{" result ( "," result )* "}"
! ;
! ; list ==>
! ;      "[]" | "[" value ( "," value )* "]" | "[" result ( "," result )* "]"
! 
  
  (defun gud-gdbmi-marker-filter (string)
    "Filter GDB/MI output."
***************
*** 1907,1952 ****
  
    ;; Start accumulating output for the GUD buffer.
    (setq gdb-filter-output "")
-   (let (output-record-list)
  
!     ;; Process all the complete markers in this chunk.
!     (dolist (gdbmi-record gdbmi-record-list)
!       (while (string-match (cdr gdbmi-record) gud-marker-acc)
! 	(push (list (match-beginning 0)
! 		    (car gdbmi-record)
! 		    (match-string 1 gud-marker-acc)
! 		    (match-string 2 gud-marker-acc)
! 		    (match-end 0))
! 	      output-record-list)
! 	(setq gud-marker-acc
! 	      (concat (substring gud-marker-acc 0 (match-beginning 0))
! 		      ;; Pad with spaces to preserve position.
! 		      (make-string (length (match-string 0 gud-marker-acc)) 32)
! 		      (substring gud-marker-acc (match-end 0))))))
! 
!     (setq output-record-list (sort output-record-list 'gdb-car<))
! 
!     (dolist (output-record output-record-list)
!       (let ((record-type (cadr output-record))
! 	    (arg1 (nth 2 output-record))
! 	    (arg2 (nth 3 output-record)))
! 	(cond ((eq record-type 'gdb-error)
! 	       (gdb-done-or-error arg2 arg1 'error))
! 	      ((eq record-type 'gdb-done)
! 	       (gdb-done-or-error arg2 arg1 'done))
! 	      ;; Suppress "No registers."  GDB 6.8 and earlier
! 	      ;; duplicates MI error message on internal stream.
! 	      ;; Don't print to GUD buffer.
! 	      ((not (and (eq record-type 'gdb-internals)
! 			 (string-equal (read arg1) "No registers.\n")))
! 	       (funcall record-type arg1)))))
  
!     (setq gdb-output-sink 'user)
!     ;; Remove padding.
!     (string-match "^ *" gud-marker-acc)
!     (setq gud-marker-acc (substring gud-marker-acc (match-end 0)))
  
!     gdb-filter-output))
  
  (defun gdb-gdb (_output-field))
  
--- 2216,2235 ----
  
    ;; Start accumulating output for the GUD buffer.
    (setq gdb-filter-output "")
  
!   (let ((acc-length (length gud-marker-acc)))
!     (catch 'gdbmi-incomplete-stream
!       (while (and (< gdbmi-bnf-offset acc-length)
! 		  (funcall gdbmi-bnf-state)))))
! 
!   (when (/= gdbmi-bnf-offset 0)
!     (setq gud-marker-acc (substring gud-marker-acc gdbmi-bnf-offset))
!     (setq gdbmi-bnf-offset 0))
  
!   (when (and gdbmi-debug-mode (> (length gud-marker-acc) 0))
!     (message "gud-gdbmi-marker-filter, unparsed string: %s" gud-marker-acc))
  
!   gdb-filter-output)
  
  (defun gdb-gdb (_output-field))
  
***************
*** 1954,1964 ****
    (setq gdb-filter-output
          (concat output-field gdb-filter-output)))
  
! (defun gdb-ignored-notification (_output-field))
  
  ;; gdb-invalidate-threads is defined to accept 'update-threads signal
! (defun gdb-thread-created (_output-field))
! (defun gdb-thread-exited (output-field)
    "Handle =thread-exited async record: unset `gdb-thread-number'
   if current thread exited and update threads list."
    (let* ((thread-id (bindat-get-field (gdb-json-string output-field) 'id)))
--- 2237,2247 ----
    (setq gdb-filter-output
          (concat output-field gdb-filter-output)))
  
! (defun gdb-ignored-notification (_token _output-field))
  
  ;; gdb-invalidate-threads is defined to accept 'update-threads signal
! (defun gdb-thread-created (_token _output-field))
! (defun gdb-thread-exited (_token output-field)
    "Handle =thread-exited async record: unset `gdb-thread-number'
   if current thread exited and update threads list."
    (let* ((thread-id (bindat-get-field (gdb-json-string output-field) 'id)))
***************
*** 1971,1977 ****
      (gdb-wait-for-pending
       (gdb-emit-signal gdb-buf-publisher 'update-threads))))
  
! (defun gdb-thread-selected (output-field)
    "Handler for =thread-selected MI output record.
  
  Sets `gdb-thread-number' to new id."
--- 2254,2260 ----
      (gdb-wait-for-pending
       (gdb-emit-signal gdb-buf-publisher 'update-threads))))
  
! (defun gdb-thread-selected (_token output-field)
    "Handler for =thread-selected MI output record.
  
  Sets `gdb-thread-number' to new id."
***************
*** 1988,1994 ****
      (gdb-wait-for-pending
       (gdb-update))))
  
! (defun gdb-running (output-field)
    (let* ((thread-id
            (bindat-get-field (gdb-json-string output-field) 'thread-id)))
      ;; We reset gdb-frame-number to nil if current thread has gone
--- 2271,2277 ----
      (gdb-wait-for-pending
       (gdb-update))))
  
! (defun gdb-running (_token output-field)
    (let* ((thread-id
            (bindat-get-field (gdb-json-string output-field) 'thread-id)))
      ;; We reset gdb-frame-number to nil if current thread has gone
***************
*** 2006,2012 ****
    (setq gdb-active-process t)
    (gdb-emit-signal gdb-buf-publisher 'update-threads))
  
! (defun gdb-starting (_output-field)
    ;; CLI commands don't emit ^running at the moment so use gdb-running too.
    (setq gdb-inferior-status "running")
    (gdb-force-mode-line-update
--- 2289,2295 ----
    (setq gdb-active-process t)
    (gdb-emit-signal gdb-buf-publisher 'update-threads))
  
! (defun gdb-starting (_output-field result)
    ;; CLI commands don't emit ^running at the moment so use gdb-running too.
    (setq gdb-inferior-status "running")
    (gdb-force-mode-line-update
***************
*** 2020,2026 ****
  
  ;; -break-insert -t didn't give a reason before gdb 6.9
  
! (defun gdb-stopped (output-field)
    "Given the contents of *stopped MI async record, select new
  current thread and update GDB buffers."
    ;; Reason is available with target-async only
--- 2303,2309 ----
  
  ;; -break-insert -t didn't give a reason before gdb 6.9
  
! (defun gdb-stopped (_token output-field)
    "Given the contents of *stopped MI async record, select new
  current thread and update GDB buffers."
    ;; Reason is available with target-async only
***************
*** 2106,2112 ****
    (setq gdb-filter-output
  	(gdb-concat-output gdb-filter-output (read output-field))))
  
! (defun gdb-done-or-error (output-field token-number type)
    (if (string-equal token-number "")
        ;; Output from command entered by user
        (progn
--- 2389,2401 ----
    (setq gdb-filter-output
  	(gdb-concat-output gdb-filter-output (read output-field))))
  
! (defun gdb-done (token-number output-field is-complete)
!   (gdb-done-or-error token-number 'done output-field is-complete))
! 
! (defun gdb-error (token-number output-field is-complete)
!   (gdb-done-or-error token-number 'error output-field is-complete))
! 
! (defun gdb-done-or-error (token-number type output-field is-complete)
    (if (string-equal token-number "")
        ;; Output from command entered by user
        (progn
***************
*** 2122,2135 ****
      ;; Output from command from frontend.
      (setq gdb-output-sink 'emacs))
  
-   (gdb-clear-partial-output)
- 
    ;; The process may already be dead (e.g. C-d at the gdb prompt).
    (let* ((proc (get-buffer-process gud-comint-buffer))
  	 (no-proc (or (null proc)
  		      (memq (process-status proc) '(exit signal)))))
  
!     (when gdb-first-done-or-error
        (unless (or token-number gud-running no-proc)
  	(setq gdb-filter-output (concat gdb-filter-output gdb-prompt-name)))
        (gdb-update no-proc)
--- 2411,2422 ----
      ;; Output from command from frontend.
      (setq gdb-output-sink 'emacs))
  
    ;; The process may already be dead (e.g. C-d at the gdb prompt).
    (let* ((proc (get-buffer-process gud-comint-buffer))
  	 (no-proc (or (null proc)
  		      (memq (process-status proc) '(exit signal)))))
  
!     (when (and is-complete gdb-first-done-or-error)
        (unless (or token-number gud-running no-proc)
  	(setq gdb-filter-output (concat gdb-filter-output gdb-prompt-name)))
        (gdb-update no-proc)
***************
*** 2138,2150 ****
      (setq gdb-filter-output
  	  (gdb-concat-output gdb-filter-output output-field))
  
!     (when token-number
        (with-current-buffer
  	  (gdb-get-buffer-create 'gdb-partial-output-buffer)
  	(funcall
  	 (cdr (assoc (string-to-number token-number) gdb-handler-alist))))
        (setq gdb-handler-alist
! 	    (assq-delete-all token-number gdb-handler-alist)))))
  
  (defun gdb-concat-output (so-far new)
    (cond
--- 2425,2443 ----
      (setq gdb-filter-output
  	  (gdb-concat-output gdb-filter-output output-field))
  
!     ;; We are done concatenating to the output sink.  Restore it to user sink:
!     (setq gdb-output-sink 'user)
! 
!     (when (and token-number is-complete)
        (with-current-buffer
  	  (gdb-get-buffer-create 'gdb-partial-output-buffer)
  	(funcall
  	 (cdr (assoc (string-to-number token-number) gdb-handler-alist))))
        (setq gdb-handler-alist
!             (assq-delete-all token-number gdb-handler-alist)))
! 
!   (when is-complete
!     (gdb-clear-partial-output))))
  
  (defun gdb-concat-output (so-far new)
    (cond

^ permalink raw reply	[flat|nested] 48+ messages in thread

* bug#10580: 24.0.92; gdb initialization takes more than one minute at 100
  2013-03-01  3:31       ` Jean-Philippe Gravel
@ 2013-03-11 17:14         ` Stefan Monnier
  0 siblings, 0 replies; 48+ messages in thread
From: Stefan Monnier @ 2013-03-11 17:14 UTC (permalink / raw)
  To: Jean-Philippe Gravel; +Cc: Chong Yidong, 10580-done

> My copyright assignment is finally complete.

> While I was waiting for that, I found a problem with my patch.  If you
> use the gdb command "finish" to exit from a function, gdb replies with
> a dump of the returned value (even though gdb-mi will not show it).
> My previous patch was failing with a regexp overflow if the return
> value was too big.  This new patch will solve this problem.

Thank you.  I just installed it with the following changes (see patch below):

- gdbmi-debug-mode is a defvar (such debug stuff doesn't deserve a defcustom).
- Use the imperative "Return ..." rather than the present tense "Returns
  ..." in docstrings, as is the convention.  I also integrated a few
  other suggestions from C-u M-x checkdoc-current-buffer (some of which
  affect code doesn't come from your patch, and there's more to fix).
- Use the new defvar-local.
- Fit within 80 columns.
- Use lexical-binding for closures.

and the following ChangeLog entry:

   2013-03-11  Jean-Philippe Gravel  <jpgravel@gmail.com>

	* progmodes/gdb-mi.el: Speed up initialization (bug#10580).
	Use lexical-binding.  Fix up docstring according to conventions.
	(gdbmi-debug-mode): New var.
	(gdbmi-start-with, gdbmi-same-start, gdbmi-is-number, gdbmi-bnf-init)
	(gdbmi-bnf-output, gdbmi-bnf-skip-unrecognized, gdbmi-bnf-gdb-prompt)
	(gdbmi-bnf-result-record, gdbmi-bnf-out-of-band-record)
	(gdbmi-bnf-async-record, gdbmi-bnf-stream-record)
	(gdbmi-bnf-console-stream-output, gdbmi-bnf-target-stream-output)
	(gdbmi-bnf-log-stream-output, gdbmi-bnf-result-and-async-record-impl)
	(gdbmi-bnf-incomplete-record-result): New functions.
	(gdb-car<): Remove function.
	(gdbmi-record-list): Remove variable.
	(gdbmi-bnf-state, gdbmi-bnf-offset): New vars.
	(gdbmi-bnf-result-state-configs): New const.
	(gud-gdbmi-marker-filter): Rewrite.
	(gdb-ignored-notification, gdb-thread-created, gdb-thread-exited)
	(gdb-thread-selected, gdb-running, gdb-starting, gdb-stopped):
	Add `token' argument.
	(gdb-done, gdb-error): New functions.
	(gdb-done-or-error): Add `is-complete' argument.  Change arg order.

Thank you very much for your help,


        Stefan


--- lisp/progmodes/gdb-mi.el	2013-03-11 11:37:36.315869212 -0400
+++ lisp/progmodes/gdb-mi.el.new	2013-03-11 11:37:16.117759642 -0400
@@ -1,4 +1,4 @@
-;;; gdb-mi.el --- User Interface for running GDB
+;;; gdb-mi.el --- User Interface for running GDB  -*- lexical-binding: t -*-
 
 ;; Copyright (C) 2007-2013 Free Software Foundation, Inc.
 
@@ -192,8 +192,8 @@
 (defvar gdb-disassembly-position nil)
 
 (defvar gdb-location-alist nil
-  "Alist of breakpoint numbers and full filenames.  Only used for files that
-Emacs can't find.")
+  "Alist of breakpoint numbers and full filenames.
+Only used for files that Emacs can't find.")
 (defvar gdb-active-process nil
   "GUD tooltips display variable values when t, and macro definitions otherwise.")
 (defvar gdb-error "Non-nil when GDB is reporting an error.")
@@ -294,9 +294,7 @@
     (funcall (cdr subscriber) signal)))
 
 (defvar gdb-buf-publisher '()
-  "Used to invalidate GDB buffers by emitting a signal in
-`gdb-update'.
-
+  "Used to invalidate GDB buffers by emitting a signal in `gdb-update'.
 Must be a list of pairs with cars being buffers and cdr's being
 valid signal handlers.")
 
@@ -327,8 +325,7 @@
   "When in non-stop mode, stopped threads can be examined while
 other threads continue to execute.
 
-GDB session needs to be restarted for this setting to take
-effect."
+GDB session needs to be restarted for this setting to take effect."
   :type 'boolean
   :group 'gdb-non-stop
   :version "23.2")
@@ -336,19 +333,18 @@
 ;; TODO Some commands can't be called with --all (give a notice about
 ;; it in setting doc)
 (defcustom gdb-gud-control-all-threads t
-  "When enabled, GUD execution commands affect all threads when
-in non-stop mode. Otherwise, only current thread is affected."
+  "When non-nil, GUD execution commands affect all threads when
+in non-stop mode.  Otherwise, only current thread is affected."
   :type 'boolean
   :group 'gdb-non-stop
   :version "23.2")
 
 (defcustom gdb-switch-reasons t
-  "List of stop reasons which cause Emacs to switch to the thread
-which caused the stop. When t, switch to stopped thread no matter
-what the reason was. When nil, never switch to stopped thread
-automatically.
+  "List of stop reasons for which Emacs should switch thread.
+When t, switch to stopped thread no matter what the reason was.
+When nil, never switch to stopped thread automatically.
 
-This setting is used in non-stop mode only. In all-stop mode,
+This setting is used in non-stop mode only.  In all-stop mode,
 Emacs always switches to the thread which caused the stop."
   ;; exited, exited-normally and exited-signaled are not
   ;; thread-specific stop reasons and therefore are not included in
@@ -404,7 +400,7 @@
   :link '(info-link "(gdb)GDB/MI Async Records"))
 
 (defcustom gdb-switch-when-another-stopped t
-  "When nil, Emacs won't switch to stopped thread if some other
+  "When nil, don't switch to stopped thread if some other
 stopped thread is already selected."
   :type 'boolean
   :group 'gdb-non-stop
@@ -447,8 +443,7 @@
   :version "23.2")
 
 (defcustom gdb-show-threads-by-default nil
-  "Show threads list buffer instead of breakpoints list by
-default."
+  "Show threads list buffer instead of breakpoints list by default."
   :type 'boolean
   :group 'gdb-buffers
   :version "23.2")
@@ -490,12 +485,12 @@
 
 (defcustom gdb-create-source-file-list t
   "Non-nil means create a list of files from which the executable was built.
- Set this to nil if the GUD buffer displays \"initializing...\" in the mode
- line for a long time when starting, possibly because your executable was
- built from a large number of files.  This allows quicker initialization
- but means that these files are not automatically enabled for debugging,
- e.g., you won't be able to click in the fringe to set a breakpoint until
- execution has already stopped there."
+Set this to nil if the GUD buffer displays \"initializing...\" in the mode
+line for a long time when starting, possibly because your executable was
+built from a large number of files.  This allows quicker initialization
+but means that these files are not automatically enabled for debugging,
+e.g., you won't be able to click in the fringe to set a breakpoint until
+execution has already stopped there."
   :type 'boolean
   :group 'gdb
   :version "23.1")
@@ -507,12 +502,8 @@
   :group 'gdb
   :version "22.1")
 
-(defcustom gdbmi-debug-mode nil
-  "When non-nil, all the messages sent or received from GDB/MI are printed in
-the *Messages* buffer."
-  :type 'boolean
-  :group 'gud
-  :version "24.3")
+(defvar gdbmi-debug-mode nil
+  "When non-nil, print the messages sent/received from GDB/MI in *Messages*.")
 
 (defun gdb-force-mode-line-update (status)
   (let ((buffer gud-comint-buffer))
@@ -577,7 +568,7 @@
 
 (defmacro gdb-gud-context-call (cmd1 &optional cmd2 noall noarg)
   "`gud-call' wrapper which adds --thread/--all options between
-CMD1 and CMD2. NOALL is the same as in `gdb-gud-context-command'.
+CMD1 and CMD2.  NOALL is the same as in `gdb-gud-context-command'.
 
 NOARG must be t when this macro is used outside `gud-def'"
   `(gud-call
@@ -610,7 +601,7 @@
 
 COMMAND-LINE is the shell command for starting the gdb session.
 It should be a string consisting of the name of the gdb
-executable followed by command-line options.  The command-line
+executable followed by command line options.  The command line
 options should include \"-i=mi\" to use gdb's MI text interface.
 Note that the old \"--annotate\" option is no longer supported.
 
@@ -1263,7 +1254,7 @@
                       (cond
                        ((> new previous)
                         ;; Add new children to list.
-                        (dotimes (dummy previous)
+                        (dotimes (_ previous)
                           (push (pop temp-var-list) var-list))
                         (dolist (child children)
                           (let ((varchild
@@ -1277,9 +1268,9 @@
                             (push varchild var-list))))
                        ;; Remove deleted children from list.
                        ((< new previous)
-                        (dotimes (dummy new)
+                        (dotimes (_ new)
                           (push (pop temp-var-list) var-list))
-                        (dotimes (dummy (- previous new))
+                        (dotimes (_ (- previous new))
                           (pop temp-var-list)))))
                   (push var1 var-list))
                 (setq var1 (pop temp-var-list)))
@@ -1511,7 +1502,7 @@
       (gdb-input
        (concat "-inferior-tty-set " tty) 'ignore))))
 
-(defun gdb-inferior-io-sentinel (proc str)
+(defun gdb-inferior-io-sentinel (proc _str)
   (when (eq (process-status proc) 'failed)
     ;; When the debugged process exits, Emacs gets an EIO error on
     ;; read from the pty, and stops listening to it.  If the gdb
@@ -1771,8 +1762,7 @@
           "*"))
 
 (defun gdb-current-context-mode-name (mode)
-  "Add thread information to MODE which is to be used as
-`mode-name'."
+  "Add thread information to MODE which is to be used as `mode-name'."
   (concat mode
           (if gdb-thread-number
               (format " [thread %s]" gdb-thread-number)
@@ -1819,7 +1809,8 @@
 ;; because we may need to update current gud-running value without
 ;; changing current thread (see gdb-running)
 (defun gdb-setq-thread-number (number)
-  "Only this function must be used to change `gdb-thread-number'
+  "Set `gdb-thread-number' to NUMBER.
+Only this function must be used to change `gdb-thread-number'
 value to NUMBER, because `gud-running' and `gdb-frame-number'
 need to be updated appropriately when current thread changes."
   ;; GDB 6.8 and earlier always output thread-id="0" when stopping.
@@ -1834,7 +1825,7 @@
 
 Note that when `gdb-gud-control-all-threads' is t, `gud-running'
 cannot be reliably used to determine whether or not execution
-control buttons should be shown in menu or toolbar. Use
+control buttons should be shown in menu or toolbar.  Use
 `gdb-running-threads-count' and `gdb-stopped-threads-count'
 instead.
 
@@ -1886,7 +1877,7 @@
 
 
 (defun gdbmi-start-with (str offset match)
-  "Returns non-nil if string STR starts with MATCH, else returns nil.
+  "Return non-nil if string STR starts with MATCH, else returns nil.
 OFFSET is the position in STR at which the comparison takes place."
   (let ((match-length (length match))
 	(str-length (- (length str) offset)))
@@ -1894,7 +1885,7 @@
       (string-equal match (substring str offset (+ offset match-length))))))
 
 (defun gdbmi-same-start (str offset match)
-  "Returns non-nil if STR and MATCH are equal up to the end of either strings, else returns nil.
+  "Return non-nil iff STR and MATCH are equal up to the end of either strings.
 OFFSET is the position in STR at which the comparison takes place."
   (let* ((str-length (- (length str) offset))
 	 (match-length (length match))
@@ -1904,28 +1895,26 @@
 		    (substring match 0 compare-length)))))
 
 (defun gdbmi-is-number (character)
-"Returns non-nil if CHARACTER is a numerical character between 0 and 9,
-else returns nil."
+  "Return non-nil iff CHARACTER is a numerical character between 0 and 9."
   (and (>= character ?0)
        (<= character ?9)))
 
 
-(defvar gdbmi-bnf-state 'gdbmi-bnf-output
-  "Current GDB/MI output parser state.  The parser is placed in a
-different state when an incomplete data steam is received from GDB.
+(defvar-local gdbmi-bnf-state 'gdbmi-bnf-output
+  "Current GDB/MI output parser state.
+The parser is placed in a different state when an incomplete data steam is
+received from GDB.
 This variable will preserve the state required to resume the parsing
 when more data arrives.")
-(make-variable-buffer-local 'gdbmi-bnf-state)
 
-(defvar gdbmi-bnf-offset 0
-  "Offset in gud-marker-acc at which the parser is reading.
+(defvar-local gdbmi-bnf-offset 0
+  "Offset in `gud-marker-acc' at which the parser is reading.
 This offset is used to be able to parse the GDB/MI message
 in-place, without the need of copying the string in a temporary buffer
 or discarding parsed tokens by substringing the message.")
-(make-variable-buffer-local 'gdbmi-bnf-offset)
 
 (defun gdbmi-bnf-init ()
-  "Initializes the GDB/MI message parser"
+  "Initialize the GDB/MI message parser."
   (setq gdbmi-bnf-state 'gdbmi-bnf-output)
   (setq gdbmi-bnf-offset 0)
   (setq gud-marker-acc ""))
@@ -1937,16 +1926,16 @@
   output ==>
        ( out-of-band-record )* [ result-record ] gdb-prompt"
 
-    (gdbmi-bnf-skip-unrecognized)
-    (while (gdbmi-bnf-out-of-band-record))
-    (gdbmi-bnf-result-record)
-    (gdbmi-bnf-gdb-prompt))
+  (gdbmi-bnf-skip-unrecognized)
+  (while (gdbmi-bnf-out-of-band-record))
+  (gdbmi-bnf-result-record)
+  (gdbmi-bnf-gdb-prompt))
 
 
 (defun gdbmi-bnf-skip-unrecognized ()
-"Used as a protection mechanism in case something goes wrong when parsing
-a GDB/MI reply message.  This function will skip characters until is encounters
-the beginning of a valid record."
+  "Skip characters until is encounters the beginning of a valid record.
+Used as a protection mechanism in case something goes wrong when parsing
+a GDB/MI reply message."
   (let ((acc-length (length gud-marker-acc))
 	(prefix-offset gdbmi-bnf-offset)
 	(prompt "(gdb) \n"))
@@ -1956,12 +1945,15 @@
       (setq prefix-offset (1+ prefix-offset)))
 
     (if (and (< prefix-offset acc-length)
-             (not (member (aref gud-marker-acc prefix-offset) '(?^ ?* ?+ ?= ?~ ?@ ?&)))
+             (not (memq (aref gud-marker-acc prefix-offset)
+                        '(?^ ?* ?+ ?= ?~ ?@ ?&)))
              (not (gdbmi-same-start gud-marker-acc gdbmi-bnf-offset prompt))
-             (string-match "\\([^^*+=~@&]+\\)" gud-marker-acc gdbmi-bnf-offset))
+             (string-match "\\([^^*+=~@&]+\\)" gud-marker-acc
+                           gdbmi-bnf-offset))
         (let ((unrecognized-str (match-string 0 gud-marker-acc)))
           (setq gdbmi-bnf-offset (match-end 0))
-	  (if gdbmi-debug-mode (message "gdbmi-bnf-skip-unrecognized: %s" unrecognized-str))
+	  (if gdbmi-debug-mode
+              (message "gdbmi-bnf-skip-unrecognized: %s" unrecognized-str))
           (gdb-shell unrecognized-str)
 	  t))))
 
@@ -2043,12 +2035,14 @@
        '&' c-string"
   (when (< gdbmi-bnf-offset (length gud-marker-acc))
     (if (and (member (aref gud-marker-acc gdbmi-bnf-offset) '(?~ ?@ ?&))
-             (string-match "\\([~@&]\\)\\(\".*?\"\\)\n" gud-marker-acc gdbmi-bnf-offset))
+             (string-match "\\([~@&]\\)\\(\".*?\"\\)\n" gud-marker-acc
+                           gdbmi-bnf-offset))
         (let ((prefix (match-string 1 gud-marker-acc))
               (c-string (match-string 2 gud-marker-acc)))
 
           (setq gdbmi-bnf-offset (match-end 0))
-          (if gdbmi-debug-mode (message "gdbmi-bnf-stream-record: %s" (match-string 0 gud-marker-acc)))
+          (if gdbmi-debug-mode (message "gdbmi-bnf-stream-record: %s"
+                                        (match-string 0 gud-marker-acc)))
 
           (cond ((string-equal prefix "~")
                  (gdbmi-bnf-console-stream-output c-string))
@@ -2059,16 +2053,16 @@
 	  t))))
 
 (defun gdbmi-bnf-console-stream-output (c-string)
-  "Handler for the console-stream-output GDB/MI output grammar rule"
+  "Handler for the console-stream-output GDB/MI output grammar rule."
   (gdb-console c-string))
 
-(defun gdbmi-bnf-target-stream-output (c-string)
-  "Handler for the target-stream-output GDB/MI output grammar rule"
+(defun gdbmi-bnf-target-stream-output (_c-string)
+  "Handler for the target-stream-output GDB/MI output grammar rule."
   ;; Not currently used.
   )
 
 (defun gdbmi-bnf-log-stream-output (c-string)
-  "Handler for the log-stream-output GDB/MI output grammar rule"
+  "Handler for the log-stream-output GDB/MI output grammar rule."
   ;; Suppress "No registers."  GDB 6.8 and earlier
   ;; duplicates MI error message on internal stream.
   ;; Don't print to GUD buffer.
@@ -2087,23 +2081,26 @@
             ("thread-selected" . (gdb-thread-selected . atomic))
             ("thread-existed" . (gdb-ignored-notification . atomic))
             ('default . (gdb-ignored-notification . atomic)))))
-  "Two dimensional alist, mapping the type and class of message to a handler function.
-Handler functions are all flagged as either 'progressive' or 'atomic'.  'progressive'
-handlers are capable of parsing incomplete messages.  They can be called several time
-with new data chunk as they arrive from GDB.  'progressive' handler must have an extra
-argument that is set to a non-nil value when the message is complete.
+  "Alist of alists, mapping the type and class of message to a handler function.
+Handler functions are all flagged as either `progressive' or `atomic'.
+`progressive' handlers are capable of parsing incomplete messages.
+They can be called several time with new data chunk as they arrive from GDB.
+`progressive' handlers must have an extra argument that is set to a non-nil
+value when the message is complete.
 
 Implement the following GDB/MI output grammar rule:
   result-class ==>
        'done' | 'running' | 'connected' | 'error' | 'exit'
 
   async-class ==>
-       'stopped' | others (where others will be added depending on the needs--this is still in development).")
+       'stopped' | others (where others will be added depending on the needs
+                           --this is still in development).")
 
 (defun gdbmi-bnf-result-and-async-record-impl ()
-  "Common implementation of the result-record and async-record rule.  Both rule share
-the same syntax.  Those records may be very large in size.  For that reason, the 'result'
-part of the  record is parsed by gdbmi-bnf-incomplete-record-result, which will keep
+  "Common implementation of the result-record and async-record rule.
+Both rules share the same syntax.  Those records may be very large in size.
+For that reason, the \"result\" part of the  record is parsed by
+`gdbmi-bnf-incomplete-record-result', which will keep
 receiving characters as they arrive from GDB until the record is complete."
   (let ((acc-length (length gud-marker-acc))
 	(prefix-offset gdbmi-bnf-offset))
@@ -2114,7 +2111,8 @@
 
     (if (and (< prefix-offset acc-length)
              (member (aref gud-marker-acc prefix-offset) '(?* ?+ ?= ?^))
-             (string-match "\\([0-9]*\\)\\([*+=^]\\)\\(.+?\\)\\([,\n]\\)" gud-marker-acc gdbmi-bnf-offset))
+             (string-match "\\([0-9]*\\)\\([*+=^]\\)\\(.+?\\)\\([,\n]\\)"
+                           gud-marker-acc gdbmi-bnf-offset))
 
         (let ((token (match-string 1 gud-marker-acc))
 	      (prefix (match-string 2 gud-marker-acc))
@@ -2124,9 +2122,11 @@
 	      class-command)
 
           (setq gdbmi-bnf-offset (match-end 0))
-	  (if gdbmi-debug-mode (message "gdbmi-bnf-result-record: %s" (match-string 0 gud-marker-acc)))
+	  (if gdbmi-debug-mode (message "gdbmi-bnf-result-record: %s"
+                                        (match-string 0 gud-marker-acc)))
 
-          (setq class-alist (cdr (assoc prefix gdbmi-bnf-result-state-configs)))
+          (setq class-alist
+                (cdr (assoc prefix gdbmi-bnf-result-state-configs)))
           (setq class-command (cdr (assoc class class-alist)))
           (if (null class-command)
               (setq class-command (cdr (assoc 'default class-alist))))
@@ -2136,14 +2136,16 @@
                   (if (equal (cdr class-command) 'progressive)
                       (funcall (car class-command) token "" complete)
                     (funcall (car class-command) token "")))
-            (setq gdbmi-bnf-state `(lambda () (gdbmi-bnf-incomplete-record-result ,token ',class-command)))
+            (setq gdbmi-bnf-state
+                  (lambda ()
+                    (gdbmi-bnf-incomplete-record-result token class-command)))
             (funcall gdbmi-bnf-state))
 	  t))))
 
 (defun gdbmi-bnf-incomplete-record-result (token class-command)
   "State of the parser used to progressively parse a result-record or async-record
-rule from an incomplete data stream.  The parser will stay in this state until the end
-of the current result or async record is reached."
+rule from an incomplete data stream.  The parser will stay in this state until
+the end of the current result or async record is reached."
   (when (< gdbmi-bnf-offset (length gud-marker-acc))
     ;; Search the data stream for the end of the current record:
     (let* ((newline-pos (string-match "\n" gud-marker-acc gdbmi-bnf-offset))
@@ -2154,10 +2156,13 @@
       ;; Update the gdbmi-bnf-offset only if the current chunk of data can
       ;; be processed by the class-command handler:
       (when (or is-complete is-progressive)
-	(setq result-str (substring gud-marker-acc gdbmi-bnf-offset newline-pos))
+	(setq result-str
+              (substring gud-marker-acc gdbmi-bnf-offset newline-pos))
 	(setq gdbmi-bnf-offset (+ 1 newline-pos)))
 
-      (if gdbmi-debug-mode (message "gdbmi-bnf-incomplete-record-result: %s" (substring gud-marker-acc gdbmi-bnf-offset newline-pos)))
+      (if gdbmi-debug-mode
+          (message "gdbmi-bnf-incomplete-record-result: %s"
+                   (substring gud-marker-acc gdbmi-bnf-offset newline-pos)))
 
       ;; Update the parsing state before invoking the handler in class-command
       ;; to make sure it's not left in an invalid state if the handler was
@@ -2171,7 +2176,8 @@
 	    (if is-complete
 		(funcall (car class-command) token result-str))))
 
-      (unless is-complete ;; Incomplete gdb response: abort the parsing until we receive more data.
+      (unless is-complete
+        ;; Incomplete gdb response: abort parsing until we receive more data.
         (if gdbmi-debug-mode (message "gdbmi-bnf-incomplete-record-result, aborting: incomplete stream"))
         (throw 'gdbmi-incomplete-stream nil))
 
@@ -2242,8 +2248,8 @@
 ;; gdb-invalidate-threads is defined to accept 'update-threads signal
 (defun gdb-thread-created (_token _output-field))
 (defun gdb-thread-exited (_token output-field)
-  "Handle =thread-exited async record: unset `gdb-thread-number'
- if current thread exited and update threads list."
+  "Handle =thread-exited async record.
+Unset `gdb-thread-number' if current thread exited and update threads list."
   (let* ((thread-id (bindat-get-field (gdb-json-string output-field) 'id)))
     (if (string= gdb-thread-number thread-id)
         (gdb-setq-thread-number nil))
@@ -2289,7 +2295,7 @@
   (setq gdb-active-process t)
   (gdb-emit-signal gdb-buf-publisher 'update-threads))
 
-(defun gdb-starting (_output-field result)
+(defun gdb-starting (_output-field _result)
   ;; CLI commands don't emit ^running at the moment so use gdb-running too.
   (setq gdb-inferior-status "running")
   (gdb-force-mode-line-update
@@ -2462,8 +2468,8 @@
 replaced with semicolons.
 
 If FIX-KEY is non-nil, strip all \"FIX-KEY=\" occurrences from
-partial output. This is used to get rid of useless keys in lists
-in MI messages, e.g.: [key=.., key=..]. -stack-list-frames and
+partial output.  This is used to get rid of useless keys in lists
+in MI messages, e.g.: [key=.., key=..].  -stack-list-frames and
 -break-info are examples of MI commands which issue such
 responses.
 
@@ -2630,16 +2636,16 @@
                                                     handler-name
                                                     &optional signal-list)
   "Define a trigger TRIGGER-NAME which sends GDB-COMMAND and sets
-HANDLER-NAME as its handler. HANDLER-NAME is bound to current
+HANDLER-NAME as its handler.  HANDLER-NAME is bound to current
 buffer with `gdb-bind-function-to-buffer'.
 
 If SIGNAL-LIST is non-nil, GDB-COMMAND is sent only when the
-defined trigger is called with an argument from SIGNAL-LIST. It's
+defined trigger is called with an argument from SIGNAL-LIST.  It's
 not recommended to define triggers with empty SIGNAL-LIST.
 Normally triggers should respond at least to 'update signal.
 
 Normally the trigger defined by this command must be called from
-the buffer where HANDLER-NAME must work. This should be done so
+the buffer where HANDLER-NAME must work.  This should be done so
 that buffer-local thread number may be used in GDB-COMMAND (by
 calling `gdb-current-context-command').
 `gdb-bind-function-to-buffer' is used to achieve this, see
@@ -2668,32 +2674,33 @@
 
 Delete ((current-buffer) . TRIGGER-NAME) from
 `gdb-pending-triggers', erase current buffer and evaluate
-CUSTOM-DEFUN. Then `gdb-update-buffer-name' is called.
+CUSTOM-DEFUN.  Then `gdb-update-buffer-name' is called.
 
 If NOPRESERVE is non-nil, window point is not restored after CUSTOM-DEFUN."
   `(defun ,handler-name ()
      (gdb-delete-pending (cons (current-buffer) ',trigger-name))
-     (let* ((buffer-read-only nil)
-            (window (get-buffer-window (current-buffer) 0))
-            (start (window-start window))
-            (p (window-point window)))
+     (let* ((inhibit-read-only t)
+            ,@(unless nopreserve
+                '((window (get-buffer-window (current-buffer) 0))
+                  (start (window-start window))
+                  (p (window-point window)))))
        (erase-buffer)
        (,custom-defun)
        (gdb-update-buffer-name)
-       ,(when (not nopreserve)
-          '(set-window-start window start)
-          '(set-window-point window p)))))
+       ,@(when (not nopreserve)
+          '((set-window-start window start)
+            (set-window-point window p))))))
 
 (defmacro def-gdb-trigger-and-handler (trigger-name gdb-command
                                                     handler-name custom-defun
                                                     &optional signal-list)
   "Define trigger and handler.
 
-TRIGGER-NAME trigger is defined to send GDB-COMMAND. See
-`def-gdb-auto-update-trigger'.
+TRIGGER-NAME trigger is defined to send GDB-COMMAND.
+See `def-gdb-auto-update-trigger'.
 
-HANDLER-NAME handler uses customization of CUSTOM-DEFUN. See
-`def-gdb-auto-update-handler'."
+HANDLER-NAME handler uses customization of CUSTOM-DEFUN.
+See `def-gdb-auto-update-handler'."
   `(progn
      (def-gdb-auto-update-trigger ,trigger-name
        ,gdb-command
@@ -3050,37 +3057,38 @@
                      gdb-running-threads-count
                    gdb-stopped-threads-count))
 
-        (gdb-table-add-row table
-                           (list
-                            (bindat-get-field thread 'id)
-                            (concat
-                             (if gdb-thread-buffer-verbose-names
-                                 (concat (bindat-get-field thread 'target-id) " ") "")
-                             (bindat-get-field thread 'state)
-                             ;; Include frame information for stopped threads
-                             (if (not running)
-                                 (concat
-                                  " in " (bindat-get-field thread 'frame 'func)
-                                  (if gdb-thread-buffer-arguments
-                                      (concat
-                                       " ("
-                                       (let ((args (bindat-get-field thread 'frame 'args)))
-                                         (mapconcat
-                                          (lambda (arg)
-                                            (apply #'format "%s=%s"
-                                                   (gdb-get-many-fields arg 'name 'value)))
-                                          args ","))
-                                       ")")
-                                    "")
-                                  (if gdb-thread-buffer-locations
-                                      (gdb-frame-location (bindat-get-field thread 'frame)) "")
-                                  (if gdb-thread-buffer-addresses
-                                      (concat " at " (bindat-get-field thread 'frame 'addr)) ""))
-                               "")))
-                           (list
-                            'gdb-thread thread
-                            'mouse-face 'highlight
-                            'help-echo "mouse-2, RET: select thread")))
+        (gdb-table-add-row
+         table
+         (list
+          (bindat-get-field thread 'id)
+          (concat
+           (if gdb-thread-buffer-verbose-names
+               (concat (bindat-get-field thread 'target-id) " ") "")
+           (bindat-get-field thread 'state)
+           ;; Include frame information for stopped threads
+           (if (not running)
+               (concat
+                " in " (bindat-get-field thread 'frame 'func)
+                (if gdb-thread-buffer-arguments
+                    (concat
+                     " ("
+                     (let ((args (bindat-get-field thread 'frame 'args)))
+                       (mapconcat
+                        (lambda (arg)
+                          (apply #'format "%s=%s"
+                                 (gdb-get-many-fields arg 'name 'value)))
+                        args ","))
+                     ")")
+                  "")
+                (if gdb-thread-buffer-locations
+                    (gdb-frame-location (bindat-get-field thread 'frame)) "")
+                (if gdb-thread-buffer-addresses
+                    (concat " at " (bindat-get-field thread 'frame 'addr)) ""))
+             "")))
+         (list
+          'gdb-thread thread
+          'mouse-face 'highlight
+          'help-echo "mouse-2, RET: select thread")))
       (when (string-equal gdb-thread-number
                           (bindat-get-field thread 'id))
         (setq marked-line (length gdb-threads-list))))
@@ -3096,8 +3104,8 @@
   "Define a NAME command which will act upon thread on the current line.
 
 CUSTOM-DEFUN may use locally bound `thread' variable, which will
-be the value of 'gdb-thread property of the current line. If
-'gdb-thread is nil, error is signaled."
+be the value of 'gdb-thread property of the current line.
+If `gdb-thread' is nil, error is signaled."
   `(defun ,name (&optional event)
      ,(when doc doc)
      (interactive (list last-input-event))
@@ -3246,7 +3254,7 @@
 (defun gdb-memory-column-width (size format)
   "Return length of string with memory unit of SIZE in FORMAT.
 
-SIZE is in bytes, as in `gdb-memory-unit'. FORMAT is a string as
+SIZE is in bytes, as in `gdb-memory-unit'.  FORMAT is a string as
 in `gdb-memory-format'."
   (let ((format-base (cdr (assoc format
                                  '(("x" . 16)
@@ -3748,8 +3756,7 @@
         (error "Not recognized as break/watchpoint line")))))
 
 (defun gdb-goto-breakpoint (&optional event)
-  "Go to the location of breakpoint at current line of
-breakpoints buffer."
+  "Go to the location of breakpoint at current line of breakpoints buffer."
   (interactive (list last-input-event))
   (if event (posn-set-point (event-end event)))
   ;; Hack to stop gdb-goto-breakpoint displaying in GUD buffer.
@@ -4133,7 +4140,7 @@
 
 (defun gdb-get-source-file-list ()
   "Create list of source files for current GDB session.
-If buffers already exist for any of these files, gud-minor-mode
+If buffers already exist for any of these files, `gud-minor-mode'
 is set in them."
   (goto-char (point-min))
   (while (re-search-forward gdb-source-file-regexp nil t)
@@ -4144,8 +4151,8 @@
 	(gdb-init-buffer)))))
 
 (defun gdb-get-main-selected-frame ()
-  "Trigger for `gdb-frame-handler' which uses main current
-thread. Called from `gdb-update'."
+  "Trigger for `gdb-frame-handler' which uses main current thread.
+Called from `gdb-update'."
   (if (not (gdb-pending-p 'gdb-get-main-selected-frame))
       (progn
 	(gdb-input (gdb-current-context-command "-stack-info-frame")
@@ -4153,7 +4160,7 @@
 	(gdb-add-pending 'gdb-get-main-selected-frame))))
 
 (defun gdb-frame-handler ()
-  "Sets `gdb-selected-frame' and `gdb-selected-file' to show
+  "Set `gdb-selected-frame' and `gdb-selected-file' to show
 overlay arrow in source buffer."
   (gdb-delete-pending 'gdb-get-main-selected-frame)
   (let ((frame (bindat-get-field (gdb-json-partial-output) 'frame)))
@@ -4214,8 +4221,8 @@
 
 (defun gdb-preempt-existing-or-display-buffer (buf &optional split-horizontal)
   "Find window displaying a buffer with the same
-`gdb-buffer-type' as BUF and show BUF there. If no such window
-exists, just call `gdb-display-buffer' for BUF. If the window
+`gdb-buffer-type' as BUF and show BUF there.  If no such window
+exists, just call `gdb-display-buffer' for BUF.  If the window
 found is already dedicated, split window according to
 SPLIT-HORIZONTAL and show BUF in the new window."
   (if buf
@@ -4603,8 +4610,7 @@
 	(gud-gdb-fetch-lines-break (length context))
 	(gud-gdb-fetched-lines nil)
 	;; This filter dumps output lines to `gud-gdb-fetched-lines'.
-	(gud-marker-filter #'gud-gdbmi-fetch-lines-filter)
-	complete-list)
+	(gud-marker-filter #'gud-gdbmi-fetch-lines-filter))
     (with-current-buffer (gdb-get-buffer 'gdb-partial-output-buffer)
       (gdb-input (concat "complete " context command)
 		 (lambda () (setq gud-gdb-fetch-lines-in-progress nil)))





^ permalink raw reply	[flat|nested] 48+ messages in thread

end of thread, other threads:[~2013-03-11 17:14 UTC | newest]

Thread overview: 48+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-01-22 12:42 bug#10580: 24.0.92; gdb initialization takes more than one minute at 100% CPU Dov Grobgeld
2012-01-23  0:53 ` Glenn Morris
     [not found]   ` <CA++fsGG4YuTtb2VC9R+GRcPN5+JSaKpkb+uO3WAX0+VXmh8HDQ@mail.gmail.com>
2012-01-23  9:21     ` Glenn Morris
2012-01-25  0:37       ` Glenn Morris
2012-01-25  8:49         ` Dov Grobgeld
2012-01-25  9:39           ` Dov Grobgeld
2012-01-25 19:05             ` Glenn Morris
2012-04-30  5:33               ` Dov Grobgeld
2012-04-30  6:36                 ` Dov Grobgeld
2012-05-06  4:13                   ` Chong Yidong
2012-05-06  4:55                     ` Dov Grobgeld
2012-05-06  5:39                       ` Chong Yidong
2012-05-06  7:06                         ` Dov Grobgeld
2012-05-07  2:53                           ` Chong Yidong
2012-05-07  5:07                             ` Dov Grobgeld
2012-05-07  6:11                               ` Chong Yidong
2012-05-07  6:26                                 ` Chong Yidong
2012-05-08  5:33                                   ` Dov Grobgeld
2012-05-08  7:56                                     ` Dov Grobgeld
2012-05-08  8:28                                       ` Chong Yidong
2012-05-08 11:59                                         ` Dov Grobgeld
2012-05-08 16:25                                           ` Chong Yidong
2012-05-08 17:47                                             ` Eli Zaretskii
2012-05-08 21:07                                               ` Dov Grobgeld
2012-05-08 21:24                                                 ` Andreas Schwab
2012-05-08 21:30                                                   ` Dov Grobgeld
2012-05-09  7:47                                                     ` Andreas Schwab
2012-05-09  8:44                                                       ` Dov Grobgeld
2012-05-09 17:36                                                         ` Eli Zaretskii
2012-05-10  6:00                                                           ` Dov Grobgeld
2012-05-10 14:13                                                             ` Chong Yidong
2012-05-10 19:07                                                               ` Dov Grobgeld
2012-05-10 20:25                                                                 ` Stefan Monnier
2012-05-11  6:33                                                                 ` Chong Yidong
2012-05-11  8:29                                                                   ` Dov Grobgeld
2012-05-11  9:47                                                                     ` Eli Zaretskii
2012-05-11 13:27                                                                       ` Chong Yidong
2012-11-05 20:36                                                                         ` Dov Grobgeld
2012-11-05 20:46                                                                           ` Eli Zaretskii
2012-11-05 23:51                                                                             ` Stefan Monnier
2012-05-10 16:32                                                             ` Eli Zaretskii
2012-05-10 18:43                                                               ` Dov Grobgeld
2012-05-08 17:38                                           ` Eli Zaretskii
2012-12-14  4:14 ` bug#10580: 24.0.92; gdb initialization takes more than one minute at 100 Jean-Philippe Gravel
2012-12-18  4:45   ` Jean-Philippe Gravel
2012-12-21  4:01     ` Chong Yidong
2013-03-01  3:31       ` Jean-Philippe Gravel
2013-03-11 17:14         ` Stefan Monnier

Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).