Skip to content

Commit ff9de4f

Browse files
Merge pull request #39 from WorksButNotTested/flush
Prevent translation block cache flush from being deferred
2 parents dc19175 + 19f6b08 commit ff9de4f

File tree

3 files changed

+40
-9
lines changed

3 files changed

+40
-9
lines changed

accel/tcg/cpu-exec.c

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -601,14 +601,6 @@ void afl_setup(void) {
601601

602602
}
603603

604-
static void afl_flush_tb(void)
605-
{
606-
CPUState *cpu;
607-
CPU_FOREACH(cpu) {
608-
tb_flush(cpu);
609-
}
610-
}
611-
612604
/* Fork server logic, invoked once we hit _start. */
613605

614606
void afl_forkserver(CPUState *cpu) {
@@ -665,7 +657,7 @@ void afl_forkserver(CPUState *cpu) {
665657
}
666658

667659
// Flush translation cache just before fork server starts.
668-
afl_flush_tb();
660+
tb_flush_sync();
669661

670662
/* All right, let's await orders... */
671663

accel/tcg/translate-all.c

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1537,6 +1537,44 @@ void tb_flush(CPUState *cpu)
15371537
}
15381538
}
15391539

1540+
/*
1541+
* If we call tb_flush, from inside cpu_exec, then it will queue do_tb_flush to
1542+
* run asyncronously. Since we wish to do this when we start the forkserver to
1543+
* flush any translated blocks which may have been translated before the
1544+
* configuration from environment variables has been parsed, this will cause the
1545+
* flush to be deferred and instead performed after the fork server is running
1546+
* resulting in the flush occurring repeatedly rather than just the once, with
1547+
* the obvious resulting performance overhead.
1548+
*
1549+
* However, we know that the fork server should be initialized when the target
1550+
* application has only a single thread (since the fork syscall will only clone
1551+
* the calling thread into the child process). Therefore, we don't need any
1552+
* synchronization with respect to any other VCPUs and can therefore perform the
1553+
* flush synchronously instead.
1554+
*/
1555+
void tb_flush_sync(void)
1556+
{
1557+
CPUState *cpu = NULL;
1558+
size_t num_cpus = 0;
1559+
1560+
if (!tcg_enabled()) {
1561+
return;
1562+
}
1563+
1564+
CPU_FOREACH(cpu) {
1565+
num_cpus++;
1566+
}
1567+
1568+
if (num_cpus != 1) {
1569+
fprintf(stderr, "Warning: More than one VCPU when attempting to flush "
1570+
"translation block cache. Skipping since we can't do it synchronously.");
1571+
return;
1572+
}
1573+
1574+
unsigned tb_flush_count = qatomic_mb_read(&tb_ctx.tb_flush_count);
1575+
do_tb_flush(cpu, RUN_ON_CPU_HOST_INT(tb_flush_count));
1576+
}
1577+
15401578
/*
15411579
* Formerly ifdef DEBUG_TB_CHECK. These debug functions are user-mode-only,
15421580
* so in order to prevent bit rot we compile them unconditionally in user-mode,

include/exec/exec-all.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -533,6 +533,7 @@ void tb_invalidate_phys_range(target_ulong start, target_ulong end);
533533
void tb_invalidate_phys_addr(AddressSpace *as, hwaddr addr, MemTxAttrs attrs);
534534
#endif
535535
void tb_flush(CPUState *cpu);
536+
void tb_flush_sync(void);
536537
void tb_phys_invalidate(TranslationBlock *tb, tb_page_addr_t page_addr);
537538
TranslationBlock *tb_htable_lookup(CPUState *cpu, target_ulong pc,
538539
target_ulong cs_base, uint32_t flags,

0 commit comments

Comments
 (0)