refactor for separation of clz software/hardware based (#985)

refactor for separation of clz software/hardware based
This commit is contained in:
Alden Torres 2016-08-05 15:51:37 -04:00 committed by Arvid Norberg
parent 1bae47479b
commit 7ea9e76b37
13 changed files with 269 additions and 68 deletions

View File

@ -114,6 +114,7 @@ set(sources
ConvertUTF
xml_parse
version
ffs
# -- extensions --
ut_pex

View File

@ -679,6 +679,7 @@ SOURCES =
session_settings
proxy_settings
file_progress
ffs
# -- extensions --
ut_pex

View File

@ -171,6 +171,7 @@ nobase_include_HEADERS = \
aux_/openssl.hpp \
aux_/byteswap.hpp \
aux_/cppint_import_export.hpp \
aux_/ffs.hpp \
\
extensions/smart_ban.hpp \
extensions/ut_metadata.hpp \

View File

@ -45,4 +45,3 @@ namespace libtorrent { namespace aux
} }
#endif // TORRENT_CPUID_HPP_INCLUDED

View File

@ -0,0 +1,53 @@
/*
Copyright (c) 2014-2016, Arvid Norberg, Alden Torres
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the distribution.
* Neither the name of the author nor the names of its
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef TORRENT_FFS_HPP_INCLUDE
#define TORRENT_FFS_HPP_INCLUDE
#include <cstdint>
#include "libtorrent/export.hpp"
#include "libtorrent/span.hpp"
namespace libtorrent { namespace aux
{
// these functions expect the range to be in big-endian byte order
TORRENT_EXTRA_EXPORT int clz_sw(span<std::uint32_t const> buf);
// if this function is called in an unsupported platform, returns -1
// consider call always clz(buf)
TORRENT_EXTRA_EXPORT int clz_hw(span<std::uint32_t const> buf);
// this function statically determines if hardware or software is used
// and expect the range to be in big-endian byte order
TORRENT_EXTRA_EXPORT int clz(span<std::uint32_t const> buf);
}}
#endif // TORRENT_FFS_HPP_INCLUDE

View File

@ -41,19 +41,12 @@ POSSIBILITY OF SUCH DAMAGE.
#include "libtorrent/config.hpp"
#include "libtorrent/assert.hpp"
#include "libtorrent/aux_/byteswap.hpp"
#include "libtorrent/aux_/ffs.hpp"
#if TORRENT_USE_IOSTREAM
#include <iosfwd>
#endif // TORRENT_USE_IOSTREAM
#ifdef max
#undef max
#endif
#ifdef min
#undef min
#endif
namespace libtorrent
{
@ -80,7 +73,7 @@ namespace libtorrent
static sha1_hash max()
{
sha1_hash ret;
memset(ret.m_number, 0xff, size());
std::memset(ret.m_number, 0xff, size());
return ret;
}
@ -90,7 +83,7 @@ namespace libtorrent
static sha1_hash min()
{
sha1_hash ret;
memset(ret.m_number, 0, size());
std::memset(ret.m_number, 0, size());
return ret;
}
@ -137,11 +130,11 @@ namespace libtorrent
// standard comparison operators
bool operator==(sha1_hash const& n) const
{
return std::equal(n.m_number, n.m_number+number_size, m_number);
return std::equal(n.m_number, n.m_number + number_size, m_number);
}
bool operator!=(sha1_hash const& n) const
{
return !std::equal(n.m_number, n.m_number+number_size, m_number);
return !std::equal(n.m_number, n.m_number + number_size, m_number);
}
bool operator<(sha1_hash const& n) const
{
@ -155,7 +148,10 @@ namespace libtorrent
return false;
}
int count_leading_zeroes() const;
int count_leading_zeroes() const
{
return aux::clz({m_number, number_size});
}
// returns a bit-wise negated copy of the sha1-hash
sha1_hash operator~() const
@ -281,4 +277,3 @@ namespace std {
}
#endif // TORRENT_SHA1_HASH_HPP_INCLUDED

View File

@ -145,6 +145,7 @@ libtorrent_rasterbar_la_SOURCES = \
xml_parse.cpp \
version.cpp \
file_progress.cpp \
ffs.cpp \
\
$(KADEMLIA_SOURCES)

110
src/ffs.cpp Normal file
View File

@ -0,0 +1,110 @@
/*
Copyright (c) 2014-2016, Arvid Norberg, Alden Torres
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the distribution.
* Neither the name of the author nor the names of its
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
#include "libtorrent/config.hpp"
#include "libtorrent/aux_/ffs.hpp"
#include "libtorrent/aux_/byteswap.hpp"
#include "libtorrent/aux_/disable_warnings_push.hpp"
#if (defined _MSC_VER && _MSC_VER >= 1600)
#include <nmmintrin.h>
#endif
#include "libtorrent/aux_/disable_warnings_pop.hpp"
namespace libtorrent { namespace aux
{
int clz_sw(span<std::uint32_t const> buf)
{
int num = int(buf.size());
std::uint32_t const* ptr = buf.data();
for (int i = 0; i < num; i++)
{
if (ptr[i] == 0) continue;
std::uint32_t v = aux::network_to_host(ptr[i]);
// http://graphics.stanford.edu/~seander/bithacks.html#IntegerLogObvious
static const int MultiplyDeBruijnBitPosition[32] =
{
0, 9, 1, 10, 13, 21, 2, 29, 11, 14, 16, 18, 22, 25, 3, 30,
8, 12, 20, 28, 15, 17, 24, 7, 19, 27, 23, 6, 26, 5, 4, 31
};
v |= v >> 1; // first round down to one less than a power of 2
v |= v >> 2;
v |= v >> 4;
v |= v >> 8;
v |= v >> 16;
return i * 32 + 31 - MultiplyDeBruijnBitPosition[
static_cast<std::uint32_t>(v * 0x07C4ACDDU) >> 27];
}
return num * 32;
}
int clz_hw(span<std::uint32_t const> buf)
{
int num = int(buf.size());
std::uint32_t const* ptr = buf.data();
for (int i = 0; i < num; i++)
{
if (ptr[i] == 0) continue;
std::uint32_t v = aux::network_to_host(ptr[i]);
#if TORRENT_HAS_BUILTIN_CLZ
return i * 32 + __builtin_clz(v);
#elif defined _MSC_VER
DWORD pos;
_BitScanReverse(&pos, v);
return i * 32 + 31 - pos;
#else
return -1;
#endif
}
return num * 32;
}
int clz(span<std::uint32_t const> buf)
{
#if TORRENT_HAS_BUILTIN_CLZ || defined _MSC_VER
return aux::clz_hw(buf);
#else
return aux::clz_sw(buf);
#endif
}
}}

View File

@ -31,7 +31,6 @@ POSSIBILITY OF SUCH DAMAGE.
*/
#include "libtorrent/sha1_hash.hpp"
#include "libtorrent/aux_/cpuid.hpp"
#include "libtorrent/hex.hpp" // to_hex, from_hex
#if TORRENT_USE_IOSTREAM
@ -63,45 +62,6 @@ namespace libtorrent
#endif // TORRENT_USE_IOSTREAM
int sha1_hash::count_leading_zeroes() const
{
int ret = 0;
for (int i = 0; i < number_size; ++i)
{
std::uint32_t v = aux::network_to_host(m_number[i]);
if (v == 0)
{
ret += 32;
continue;
}
#if TORRENT_HAS_BUILTIN_CLZ
return ret + __builtin_clz(v);
#elif TORRENT_HAS_SSE && defined _MSC_VER
DWORD pos;
_BitScanReverse(&pos, v);
return ret + 31 - pos;
#else
// http://graphics.stanford.edu/~seander/bithacks.html#IntegerLogObvious
static const int MultiplyDeBruijnBitPosition[32] =
{
0, 9, 1, 10, 13, 21, 2, 29, 11, 14, 16, 18, 22, 25, 3, 30,
8, 12, 20, 28, 15, 17, 24, 7, 19, 27, 23, 6, 26, 5, 4, 31
};
v |= v >> 1; // first round down to one less than a power of 2
v |= v >> 2;
v |= v >> 4;
v |= v >> 8;
v |= v >> 16;
return ret + MultiplyDeBruijnBitPosition[
static_cast<std::uint32_t>(v * 0x07C4ACDDU) >> 27];
#endif
}
return ret;
}
sha1_hash& sha1_hash::operator<<=(int n)
{
TORRENT_ASSERT(n >= 0);
@ -130,12 +90,12 @@ namespace libtorrent
for (int i = 0; i < number_size - 1; ++i)
{
m_number[i] <<= n;
m_number[i+1] = aux::network_to_host(m_number[i+1]);
m_number[i] |= m_number[i+1] >> (32 - n);
m_number[i + 1] = aux::network_to_host(m_number[i + 1]);
m_number[i] |= m_number[i + 1] >> (32 - n);
m_number[i] = aux::host_to_network(m_number[i]);
}
m_number[number_size-1] <<= n;
m_number[number_size-1] = aux::host_to_network(m_number[number_size-1]);
m_number[number_size - 1] <<= n;
m_number[number_size - 1] = aux::host_to_network(m_number[number_size - 1]);
}
return *this;
}
@ -162,13 +122,13 @@ namespace libtorrent
// byte order, so they have to be byteswapped before
// applying the shift operations, and then byteswapped
// back again.
m_number[number_size-1] = aux::network_to_host(m_number[number_size-1]);
m_number[number_size - 1] = aux::network_to_host(m_number[number_size - 1]);
for (int i = number_size - 1; i > 0; --i)
{
m_number[i] >>= n;
m_number[i-1] = aux::network_to_host(m_number[i-1]);
m_number[i] |= (m_number[i-1] << (32 - n)) & 0xffffffff;
m_number[i - 1] = aux::network_to_host(m_number[i - 1]);
m_number[i] |= (m_number[i - 1] << (32 - n)) & 0xffffffff;
m_number[i] = aux::host_to_network(m_number[i]);
}
m_number[0] >>= n;
@ -178,4 +138,3 @@ namespace libtorrent
}
}

View File

@ -153,6 +153,7 @@ test-suite libtorrent :
[ run test_sha1_hash.cpp ]
[ run test_bitfield.cpp ]
[ run test_crc32.cpp ]
[ run test_ffs.cpp ]
[ run test_receive_buffer.cpp ]
[ run test_alert_manager.cpp ]
[ run test_magnet.cpp ]
@ -230,6 +231,7 @@ alias arm-tests :
test_sha1_hash
test_bitfield
test_crc32
test_ffs
;
explicit arm-tests ;

View File

@ -43,7 +43,8 @@ test_programs = \
test_enum_net \
test_file_progress \
test_linked_list \
test_direct_dht
test_direct_dht \
test_ffs
if ENABLE_TESTS
check_PROGRAMS = $(test_programs)
@ -224,6 +225,7 @@ test_remap_files_SOURCES = test_remap_files.cpp
test_file_progress_SOURCES = test_file_progress.cpp
test_linked_list_SOURCES = test_linked_list.cpp
test_direct_dht_SOURCES = test_direct_dht.cpp
test_ffs_SOURCES = test_ffs.cpp
LDADD = libtest.la $(top_builddir)/src/libtorrent-rasterbar.la

81
test/test_ffs.cpp Normal file
View File

@ -0,0 +1,81 @@
/*
Copyright (c) 2015, Arvid Norberg, Alden Torres
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the distribution.
* Neither the name of the author nor the names of its
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
#include "test.hpp"
#include "libtorrent/span.hpp"
#include "libtorrent/hex.hpp" // from_hex
#include "libtorrent/aux_/ffs.hpp"
using namespace libtorrent;
static void to_binary(char const* s, std::uint32_t* buf)
{
aux::from_hex({s, 40}, reinterpret_cast<char*>(&buf[0]));
}
TORRENT_TEST(clz)
{
std::vector<std::pair<char const*, int>> const tests = {
{ "ffffffffffffffffffffffffffffffffffffffff", 0 },
{ "0000000000000000000000000000000000000000", 160 },
{ "fff0000000000000000000000000000000000000", 0 },
{ "7ff0000000000000000000000000000000000000", 1 },
{ "3ff0000000000000000000000000000000000000", 2 },
{ "1ff0000000000000000000000000000000000000", 3 },
{ "0ff0000000000000000000000000000000000000", 4 },
{ "07f0000000000000000000000000000000000000", 5 },
{ "03f0000000000000000000000000000000000000", 6 },
{ "01f0000000000000000000000000000000000000", 7 },
{ "00f0000000000000000000000000000000000000", 8 },
{ "0070000000000000000000000000000000000000", 9 },
{ "0030000000000000000000000000000000000000", 10 },
{ "0010000000000000000000000000000000000000", 11 },
{ "0000000ffff00000000000000000000000000000", 28 },
{ "00000007fff00000000000000000000000000000", 29 },
{ "00000003fff00000000000000000000000000000", 30 },
{ "00000001fff00000000000000000000000000000", 31 },
{ "00000000fff00000000000000000000000000000", 32 },
{ "000000007ff00000000000000000000000000000", 33 },
{ "000000003ff00000000000000000000000000000", 34 },
{ "000000001ff00000000000000000000000000000", 35 },
};
for (auto const& t : tests)
{
std::fprintf(stderr, "%s\n", t.first);
std::uint32_t buf[5];
to_binary(t.first, buf);
TEST_EQUAL(aux::clz_sw({buf, 5}), t.second);
TEST_EQUAL(aux::clz_hw({buf, 5}), t.second);
TEST_EQUAL(aux::clz({buf, 5}), t.second);
}
}

View File

@ -143,8 +143,4 @@ TORRENT_TEST(count_leading_zeroes)
std::fprintf(stderr, "%s\n", t.first);
TEST_EQUAL(to_hash(t.first).count_leading_zeroes(), t.second);
}
#if TORRENT_HAS_ARM && !TORRENT_HAS_BUILTIN_CLZ
#error "expected built-in clz for arm architecture"
#endif
}