mirror of
https://github.com/libretro/RetroArch.git
synced 2026-11-07 08:36:02 -10:00
(Rewind) A long dirty run is copied with memcpy
A delta's typical dirty run is a few words, where a call costs more than the loop that copies them; a redrawn framebuffer or tilemap is one run of thousands. From thirty-two words a run is a memcpy, on both the encode and the decode. The format is unchanged and the harness's round-trips cover both paths. On a 4 MiB state with a 64 KiB region redrawn and scattered few-word changes, x86-64 -O2: the encode 0.47 to 0.38 ms; the decode's share is a few hundredths of a millisecond either way, under the block copy that precedes it.
This commit is contained in:
1 parent
b29974db78
commit
75cc91f8e1
1 file changed
+22
-9
+22
-9
@@ -44,6 +44,13 @@
|
||||
/* Keep it off unless you're chasing a core bug, it slows things down. */
|
||||
#define STRICT_BUF_SIZE 0
|
||||
|
||||
/* A dirty run of this many words or more is copied with memcpy; a
|
||||
* shorter one by the loop, which for the few-word runs that dominate
|
||||
* a delta costs less than a call. */
|
||||
#ifndef STATE_MANAGER_MEMCPY_WORDS
|
||||
#define STATE_MANAGER_MEMCPY_WORDS 32
|
||||
#endif
|
||||
|
||||
#ifndef UINT16_MAX
|
||||
#define UINT16_MAX 0xffff
|
||||
#endif
|
||||
@@ -313,8 +320,14 @@ static size_t state_manager_raw_compress(const void *src,
|
||||
*compressed16++ = changed;
|
||||
*compressed16++ = skip;
|
||||
|
||||
for (i = 0; i < changed; i++)
|
||||
compressed16[i] = old16[i];
|
||||
/* The typical dirty run is a few words, where a call costs more
|
||||
* than the loop; a long one - a framebuffer, a redrawn tilemap -
|
||||
* is a copy. */
|
||||
if (changed >= STATE_MANAGER_MEMCPY_WORDS)
|
||||
memcpy(compressed16, old16, changed * sizeof(uint16_t));
|
||||
else
|
||||
for (i = 0; i < changed; i++)
|
||||
compressed16[i] = old16[i];
|
||||
|
||||
old16 += changed;
|
||||
new16 += changed;
|
||||
@@ -398,13 +411,13 @@ static bool state_manager_raw_decompress(const void *patch, size_t patch_len,
|
||||
|
||||
out16 += *p++;
|
||||
|
||||
/* We could do memcpy, but it seems that memcpy has a
|
||||
* constant-per-call overhead that actually shows up.
|
||||
*
|
||||
* Our average size in here seems to be 8 or something.
|
||||
* Therefore, we do something with lower overhead. */
|
||||
for (i = 0; i < numchanged; i++)
|
||||
out16[i] = p[i];
|
||||
/* The typical run is a few words, where a call costs more
|
||||
* than the loop; a long one is a copy. */
|
||||
if (numchanged >= STATE_MANAGER_MEMCPY_WORDS)
|
||||
memcpy(out16, p, numchanged * sizeof(uint16_t));
|
||||
else
|
||||
for (i = 0; i < numchanged; i++)
|
||||
out16[i] = p[i];
|
||||
|
||||
p += numchanged;
|
||||
out16 += numchanged;
|
||||
|
||||
Reference in new issue
Block a user