2
0
mirror of https://github.com/openvswitch/ovs synced 2025-10-29 15:28:56 +00:00
Files
openvswitch/lib/hash-aarch64.h
Yanqin Wei (Arm Technology China) 2525148ab3 hash: Implement hash for aarch64 using CRC32c intrinsics.
This commit adds lib/hash-aarch64.h to implement hash for aarch64.
It is based on aarch64 built-in CRC32c intrinsics, which accelerates
hash function for datapath performance.

test:
1. "test-hash" case passed in aarch64 platform.
2.  OVS-DPDK datapth performance test was run(NIC to NIC).
    Test bed: aarch64(Centriq 2400) platform.
    Test case: DPCLS forwarding(disable EMC + avg 10 subtable lookups)
    Test result: improve around 10%.

Signed-off-by: Yanqin Wei <yanqin.wei@arm.com>
Signed-off-by: Ben Pfaff <blp@ovn.org>
2019-01-25 12:57:16 -08:00

151 lines
4.2 KiB
C

/*
* Copyright (c) 2019 Arm Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/* This header implements HASH operation primitives on aarch64. */
#ifndef HASH_AARCH64_H
#define HASH_AARCH64_H 1
#ifndef HASH_H
#error "This header should only be included indirectly via hash.h."
#endif
#ifdef __cplusplus
extern "C" {
#endif
#include <arm_acle.h>
static inline uint32_t hash_add(uint32_t hash, uint32_t data)
{
return __crc32cw(hash, data);
}
/* Add the halves of 'data' in the memory order. */
static inline uint32_t hash_add64(uint32_t hash, uint64_t data)
{
return __crc32cd(hash, data);
}
static inline uint32_t hash_finish(uint32_t hash, uint64_t final)
{
/* The finishing multiplier 0x805204f3 has been experimentally
* derived to pass the testsuite hash tests. */
hash = __crc32cd(hash, final) * 0x805204f3;
return hash ^ hash >> 16; /* Increase entropy in LSBs. */
}
/* Returns the hash of the 'n' 32-bit words at 'p_', starting from 'basis'.
* We access 'p_' as a uint64_t pointer.
*
* This is inlined for the compiler to have access to the 'n_words', which
* in many cases is a constant. */
static inline uint32_t
hash_words_inline(const uint32_t p_[], size_t n_words, uint32_t basis)
{
const uint64_t *p = (const void *)p_;
uint32_t hash1 = basis;
uint32_t hash2 = 0;
uint32_t hash3 = n_words;
const uint32_t *endp = (const uint32_t *)p + n_words;
const uint64_t *limit = p + n_words / 2 - 3;
while (p <= limit) {
hash1 = __crc32cd(hash1, p[0]);
hash2 = __crc32cd(hash2, p[1]);
hash3 = __crc32cd(hash3, p[2]);
p += 3;
}
switch (endp - (const uint32_t *)p) {
case 1:
hash1 = __crc32cw(hash1, *(const uint32_t *)&p[0]);
break;
case 2:
hash1 = __crc32cd(hash1, p[0]);
break;
case 3:
hash1 = __crc32cd(hash1, p[0]);
hash2 = __crc32cw(hash2, *(const uint32_t *)&p[1]);
break;
case 4:
hash1 = __crc32cd(hash1, p[0]);
hash2 = __crc32cd(hash2, p[1]);
break;
case 5:
hash1 = __crc32cd(hash1, p[0]);
hash2 = __crc32cd(hash2, p[1]);
hash3 = __crc32cw(hash3, *(const uint32_t *)&p[2]);
break;
}
return hash_finish(hash1, (uint64_t)hash2 << 32 | hash3);
}
/* A simpler version for 64-bit data.
* 'n_words' is the count of 64-bit words, basis is 64 bits. */
static inline uint32_t
hash_words64_inline(const uint64_t p[], size_t n_words, uint32_t basis)
{
uint32_t hash1 = basis;
uint32_t hash2 = 0;
uint32_t hash3 = n_words;
const uint64_t *endp = p + n_words;
const uint64_t *limit = endp - 3;
while (p <= limit) {
hash1 = __crc32cd(hash1, p[0]);
hash2 = __crc32cd(hash2, p[1]);
hash3 = __crc32cd(hash3, p[2]);
p += 3;
}
switch (endp - p) {
case 1:
hash1 = __crc32cd(hash1, p[0]);
break;
case 2:
hash1 = __crc32cd(hash1, p[0]);
hash2 = __crc32cd(hash2, p[1]);
break;
}
return hash_finish(hash1, (uint64_t)hash2 << 32 | hash3);
}
static inline uint32_t hash_uint64_basis(const uint64_t x,
const uint32_t basis)
{
/* '23' chosen to mix bits enough for the test-hash to pass. */
return hash_finish(hash_add64(basis, x), 23);
}
static inline uint32_t hash_uint64(const uint64_t x)
{
return hash_uint64_basis(x, 0);
}
static inline uint32_t hash_2words(uint32_t x, uint32_t y)
{
return hash_uint64((uint64_t)y << 32 | x);
}
static inline uint32_t hash_pointer(const void *p, uint32_t basis)
{
return hash_uint64_basis((uint64_t) (uintptr_t) p, basis);
}
#ifdef __cplusplus
}
#endif
#endif /* hash-aarch64.h */