Better optimized CRC call when writing the content file

This saves about 15% of CPU time in writing.
This commit is contained in:
Andrea Mazzoleni 2015-10-08 22:09:12 +02:00
parent aa34b76203
commit 0ba7e649d1
4 changed files with 83 additions and 50 deletions

View file

@ -562,9 +562,10 @@ int swrite(const void* void_data, unsigned size, STREAM* f)
/* optimized version with all the data in memory */
unsigned char* pos = sptrget(f);
f->crc_stream = crc32c_plain(f->crc_stream, data, size);
/* copy it */
while (size--) {
f->crc_stream = crc32c_plain(f->crc_stream, *data);
*pos++ = *data++;
}

View file

@ -345,7 +345,7 @@ static inline int sputc(int c, STREAM* s)
if (sflush(s) != 0)
return -1;
}
s->crc_stream = crc32c_plain(s->crc_stream, c);
s->crc_stream = crc32c_plain_char(s->crc_stream, c);
*s->pos++ = c;
return 0;
}

View file

@ -350,22 +350,15 @@ uint32_t CRC32C_3[256] = {
0x4a21617b, 0x9764cbc3, 0xf54642fa, 0x2803e842
};
#if HAVE_SSE42
int crc_x86;
#endif
uint32_t crc32c_gen(uint32_t crc, const unsigned char* ptr, unsigned size)
{
crc ^= CRC_IV;
while (size >= 4) {
crc ^= ptr[0] | (uint32_t)ptr[1] << 8 | (uint32_t)ptr[2] << 16 | (uint32_t)ptr[3] << 24;
crc = CRC32C_3[crc & 0xff] ^ CRC32C_2[(crc >> 8) & 0xff] ^ CRC32C_1[(crc >> 16) & 0xff] ^ CRC32C_0[crc >> 24];
ptr += 4;
size -= 4;
}
while (size) {
crc = CRC32C_0[(crc ^ *ptr) & 0xff] ^ (crc >> 8);
++ptr;
--size;
}
crc = crc32c_gen_plain(crc, ptr, size);
crc ^= CRC_IV;
@ -375,33 +368,9 @@ uint32_t crc32c_gen(uint32_t crc, const unsigned char* ptr, unsigned size)
#if HAVE_SSE42
uint32_t crc32c_x86(uint32_t crc, const unsigned char* ptr, unsigned size)
{
#ifdef CONFIG_X86_64
uint64_t crc64;
#endif
crc ^= CRC_IV;
#ifdef CONFIG_X86_64
crc64 = crc;
while (size >= 8) {
asm("crc32q %1, %0\n" : "+r" (crc64) : "m" (*(const uint64_t*)ptr));
ptr += 8;
size -= 8;
}
crc = crc64;
#else
while (size >= 4) {
asm("crc32l %1, %0\n" : "+r" (crc) : "m" (*(const uint32_t*)ptr));
ptr += 4;
size -= 4;
}
#endif
while (size) {
asm("crc32b %1, %0\n" : "+r" (crc) : "m" (*ptr));
++ptr;
--size;
}
crc = crc32c_x86_plain(crc, ptr, size);
crc ^= CRC_IV;
@ -411,10 +380,6 @@ uint32_t crc32c_x86(uint32_t crc, const unsigned char* ptr, unsigned size)
uint32_t (*crc32c)(uint32_t crc, const unsigned char* ptr, unsigned size);
#if HAVE_SSE42
int crc_x86;
#endif
void crc32c_init(void)
{
crc32c = crc32c_gen;

View file

@ -61,33 +61,100 @@ extern uint32_t CRC32C_1[256];
extern uint32_t CRC32C_2[256];
extern uint32_t CRC32C_3[256];
#if HAVE_SSE42
/**
* If the CPU support the CRC instructions.
*/
#if HAVE_SSE42
extern int crc_x86;
#endif
/**
* Compute CRC-32 (Castagnoli) for a single byte without IV.
* Compute CRC-32 (Castagnoli) for a single byte without the IV.
*/
static inline uint32_t crc32c_plain(uint32_t crc, unsigned char c)
static inline uint32_t crc32c_plain_char(uint32_t crc, unsigned char c)
{
#if HAVE_SSE42
if (tommy_likely(crc_x86)) {
asm("crc32b %1, %0\n" : "+r" (crc) : "m" (c));
return crc;
} else
#endif
{
return CRC32C_0[(crc ^ c) & 0xff] ^ (crc >> 8);
}
#endif
return CRC32C_0[(crc ^ c) & 0xff] ^ (crc >> 8);
}
/**
* Compute the CRC-32 (Castagnoli) without the IV.
*/
static inline uint32_t crc32c_gen_plain(uint32_t crc, const unsigned char* ptr, unsigned size)
{
while (size >= 4) {
crc ^= ptr[0] | (uint32_t)ptr[1] << 8 | (uint32_t)ptr[2] << 16 | (uint32_t)ptr[3] << 24;
crc = CRC32C_3[crc & 0xff] ^ CRC32C_2[(crc >> 8) & 0xff] ^ CRC32C_1[(crc >> 16) & 0xff] ^ CRC32C_0[crc >> 24];
ptr += 4;
size -= 4;
}
while (size) {
crc = CRC32C_0[(crc ^ *ptr) & 0xff] ^ (crc >> 8);
++ptr;
--size;
}
return crc;
}
/**
* Compute the CRC-32 (Castagnoli) without the IV.
*/
#if HAVE_SSE42
static inline uint32_t crc32c_x86_plain(uint32_t crc, const unsigned char* ptr, unsigned size)
{
#ifdef CONFIG_X86_64
uint64_t crc64 = crc;
while (size >= 8) {
asm("crc32q %1, %0\n" : "+r" (crc64) : "m" (*(const uint64_t*)ptr));
ptr += 8;
size -= 8;
}
crc = crc64;
#else
while (size >= 4) {
asm("crc32l %1, %0\n" : "+r" (crc) : "m" (*(const uint32_t*)ptr));
ptr += 4;
size -= 4;
}
#endif
while (size) {
asm("crc32b %1, %0\n" : "+r" (crc) : "m" (*ptr));
++ptr;
--size;
}
return crc;
}
#endif
/**
* Compute CRC-32 (Castagnoli) without the IV.
*/
static inline uint32_t crc32c_plain(uint32_t crc, const unsigned char* ptr, unsigned size)
{
#if HAVE_SSE42
if (tommy_likely(crc_x86)) {
return crc32c_x86_plain(crc, ptr, size);
}
#endif
return crc32c_gen_plain(crc, ptr, size);
}
/**
* Compute the CRC-32 (Castagnoli)
*/
uint32_t (*crc32c)(uint32_t crc, const unsigned char* ptr, unsigned size);
/**
* Internal entry points for testing.
*/
uint32_t crc32c_gen(uint32_t crc, const unsigned char* ptr, unsigned size);
uint32_t crc32c_x86(uint32_t crc, const unsigned char* ptr, unsigned size);