From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mailman by lists.gnu.org with tmda-scanned (Exim 4.43) id 1KM1HW-0006gb-SM for qemu-devel@nongnu.org; Thu, 24 Jul 2008 09:54:58 -0400 Received: from exim by lists.gnu.org with spam-scanned (Exim 4.43) id 1KM1HV-0006fP-IX for qemu-devel@nongnu.org; Thu, 24 Jul 2008 09:54:58 -0400 Received: from [199.232.76.173] (port=54260 helo=monty-python.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1KM1HV-0006fK-C6 for qemu-devel@nongnu.org; Thu, 24 Jul 2008 09:54:57 -0400 Received: from yx-out-1718.google.com ([74.125.44.154]:17161) by monty-python.gnu.org with esmtp (Exim 4.60) (envelope-from ) id 1KM1HV-0000xq-2y for qemu-devel@nongnu.org; Thu, 24 Jul 2008 09:54:57 -0400 Received: by yx-out-1718.google.com with SMTP id 3so613741yxi.82 for ; Thu, 24 Jul 2008 06:54:56 -0700 (PDT) Message-ID: <3e1533500807240654x67920d8ao55c420390f421ee3@mail.gmail.com> Date: Thu, 24 Jul 2008 14:54:55 +0100 From: "Luis Pureza" Sender: pureza@gmail.com Subject: Re: [Qemu-devel] Weird behavior while using the instruction counter In-Reply-To: <200807241344.35106.paul@codesourcery.com> MIME-Version: 1.0 Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: 7bit Content-Disposition: inline References: <3e1533500807240342s15e6e508kd1d49152b0892e9f@mail.gmail.com> <200807241344.35106.paul@codesourcery.com> Reply-To: qemu-devel@nongnu.org List-Id: qemu-devel.nongnu.org List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: Paul Brook Cc: qemu-devel@nongnu.org On Thu, Jul 24, 2008 at 1:44 PM, Paul Brook wrote: > On Thursday 24 July 2008, Luis Pureza wrote: >> Hi, >> >> I'm using the instruction counter to execute N instructions at a time. >> With very small values of N (say, N < 10), I observed the following >> behavior: >> >> 1. A new TB is generated and execution starts there; >> 2. The instruction counter timer expires and cpu_exec_nocache() is called; >> 3. cpu_exec_nocache() generates a new TB for the same PC and starts to >> execute it; >> 4. Some instruction inside the TB turns out to be an I/O instruction. >> Thus, cpu_io_recompile() gets called >> 5; cpu_io_recompile() regenerates the TB and longjmps back to the >> beginning of cpu_exec() >> 6. on cpu_exec(), tb_find_fast() returns the first TB, instead of the >> one generated by cpu_io_recompile() >> 7. Endless loop! > > I think I can see how this could happen, but only when the IO instruction is > the first instruction in the block. For any other TB you probably get > run+fault first. > >> Actually, for some reason beyond my comprehension, the loop is not >> really infinite: after a few seconds it actually executes the block >> and moves on. However, as you can imagine, this is too slow. > > You need to figure out what's actually happening. Either it's an infinite loop > or it's not. I'm not sure of this, but I think I know what was happening. Since the first TB was never cleared, the number of TBs would grow forever... until it filled the code generation buffer. That's when tb_find_pc() would actually find the correct TB instead of the old one and execute it. And it started to move again. > Instruction counter expiry and the first IO trap are both fairly expensive > operation. Having the counter expire every few instructionswill make qemu go > extremely slowly. Are you sure it's not just running very slowly? > >> I think I fixed the problem by appending CF_LAST_IO to the cflags of >> the TB generated by cpu_exec_nocache(). This way, cpu_io_recompile() >> won't be called for this TB. > > No. You're assuming the IO trap occurs on the last instruction, which not > true. The problem is that cpu_exec_nocache introduces a second TB with the > same lookup key(pc+flags). cpu_io_recompile (and possibly other places) > assume the currently executing TB is the only tb that matches. It needs to > invalidate the original TB (if it exists) as well as the uncached one. Obviously, you're right. I was testing with blocks of a single instruction. What do you think of this: if (tb != &tbs[0] && (tb - 1)->pc == tb->pc) { tb_phys_invalidate(tb - 1, -1); } added to cpu_io_recompile() just after the if (!tb) check? Seems to do the trick for me... Thanks, Luis Pureza