New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
ocamldebug became very slow #9606
Comments
Could you post a script that reproduces the observed slowness? I.e. an operation that takes > 10 seconds. Reports without a repro case are unusable. |
(Clarification: by "script" I mean at least a transcript of an ocamldebug session. Not necessarily a fully automated shell script, even though that would be nice too.) |
Just one line is enough:
Up to 4.09 this takes less than 1s to run and exit, but since 4.10 this takes about 30s of wall time (but only 0.7s of user time, and 0.1s of system time, which seem both unchanged). Quite mysterious to me. This looks like the process is waiting a lot, doesn't it ? |
This looks like something that one can use |
It appears that the debugger is creating ~71k breakpoints using |
Maybe the feature we merged to allow debugging of dynlinked code? |
|
#8654 introduced the O(n) |
But n = 1 here, no? For a bytecode executable that does not use dynamic linking, there is only one code fragment.
That sounds expensive, and I can't remember the original ocamldebug doing this. |
If I read the code correctly, code fragments are indexed in an extensible table |
(If I understand the code correctly, |
Indeed, debug events are replaced by a special EVENT instruction, whose purpose is (among others) to decrease
This is atrocious, indeed. Someone failed algorithms 101. |
It's probably more of a case of someone not realizing what the complexity constraints/requirement were for this particular piece of code. (In particular, it is natural to assume that there are few breakpoints set during a debugging session.) |
Yes, this surprised me also, to the point that I assumed the problem was in ocamldebug. (If I understand correctly now, what the C code calls "breakpoint" includes all debug events, regardless of whether the user has set breakpoints or not). |
Would be good to document this with the fix so it doesn't happen again. |
@bluddy would you be interested in submitting a fix for this issue? I would expect that moving from a linear-search bag to a (frag+pc)-indexed table for "saved instructions" is not very hard (I was considering giving it a go myself). One would have to look at how the code-fragment table evolves (only in the bytecode runtime). Either we have to evolve the new table at the same time (this may require factorizing the changes to the code-fragment table into functions?), or maybe it is enough to create new entries in the saved-instruction table on-demand, on the first attempt to save an instruction in this fragment. (If the code-fragments table can shrink by removing elements, then the on-demand strategy would not be good, as we risk keeping those saved-instruction fragments indefinitely and having a leak.) |
I think we can rescue the current implementation by using binary search and sorting the array on demand, taking advantage of the fact that we have sequences of insertions followed by long sequences of searches, so the cost of sorting is amortized. |
I'll give it a shot @gasche. I'll try @xavierleroy's simple suggestion first. |
I'm sorry to come after the battle, but I don't think @xavierleroy's idea is the way to go, for two reasons: 1- It will require to add an instruction to the interface between the debugger UI and the interpreter. This is not nice, because it will also require enforcing an additional invariant that the sorting instruction is emitted before any use of the table. 2- Unloading a code fragment will still require linear scans in the table, and thus a quadratic behavior in the worst case. I think we should either use one dynamically allocated array for each fragment or a hash table. |
I'm worried that the sorting approach could give code that is less clear, in the final version, than a copy-of-fragments approach (in addition to having a less interesting / more complex performance profile). But I guess that it is worth giving it a shot. |
@jhjourdan I don'tt think we would need a sorting instruction. We could have a flag to remember if the array is sorted, set it when we sort and unset it when we add an element. But I agree that this is yet another piece of state to keep around. |
Yes, I was thinking along these lines. But it is tricky to know when it is a good time to sort. If nothing clever is proposed, I'll offer something based on the skip list library we already have (in globroots.c). |
…ebugger This avoids the quadratic behaviors of the previous array-based implementation. Closes: ocaml#9606
…ebugger This avoids the quadratic behaviors of the previous array-based implementation. Closes: ocaml#9606
See PR#9635. @garrigue 's repro (#9606 (comment)) takes 0.6 seconds on my machine. |
…ebugger This avoids the quadratic behaviors of the previous array-based implementation. Closes: ocaml#9606
I note that Coq developpers asked for #8654 with tears, but apparently did not even tried it, since they would have noticed the bug. (That's not without having noticed them in #8654 (comment).). Cc @ppedrot, @maximedenes |
To play the "good cop" for once: let me speculate that traditional ocamldebug-users (among Coq developers) are using older OCaml version for development, using Emilio's static-linking workaround to debug plugins, and they haven't yet adapted their workflows to the new feature (... or, apparently, tried ocamldebug under OCaml 4.10). This makes sense in the wider context: 4.10 has only been out for a bit more than three months, and the first report of this issue was only 13 days ago. |
I confirm @gasche's speculations: the most recent OCaml version I personally use for daily Coq development is 4.08. Furthermore, Coq was made compatible with OCaml 4.10 only quite recently. |
You miss all our good new stuff and also our bad new stuff. |
Introduce a library of skip lists and use them to fix a performance issue in the debugger (issue #9606)
@xavierleroy Thanks ! |
Introduce a library of skip lists and use them to fix a performance issue in the debugger (issue ocaml#9606)
Introduce a library of skip lists and use them to fix a performance issue in the debugger (issue ocaml#9606)
I use frequently
ocamldebug
to debugocamlc
itself, and recently it became very slow.I have to wait more than 10 seconds for things that took less than 1 second (in my qualitative memory...)
I am using trunk (4.12) on MacOSX Mojave.
The text was updated successfully, but these errors were encountered: