diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-27 18:24:20 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-27 18:24:20 +0000 |
commit | 483eb2f56657e8e7f419ab1a4fab8dce9ade8609 (patch) | |
tree | e5d88d25d870d5dedacb6bbdbe2a966086a0a5cf /src/boost/libs/context/performance | |
parent | Initial commit. (diff) | |
download | ceph-upstream.tar.xz ceph-upstream.zip |
Adding upstream version 14.2.21.upstream/14.2.21upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/boost/libs/context/performance')
-rw-r--r-- | src/boost/libs/context/performance/callcc/Jamfile.v2 | 34 | ||||
-rw-r--r-- | src/boost/libs/context/performance/callcc/performance.cpp | 102 | ||||
-rw-r--r-- | src/boost/libs/context/performance/clock.hpp | 45 | ||||
-rw-r--r-- | src/boost/libs/context/performance/cycle.hpp | 26 | ||||
-rw-r--r-- | src/boost/libs/context/performance/cycle_i386.hpp | 83 | ||||
-rw-r--r-- | src/boost/libs/context/performance/cycle_x86-64.hpp | 79 | ||||
-rw-r--r-- | src/boost/libs/context/performance/fcontext/Jamfile.v2 | 34 | ||||
-rw-r--r-- | src/boost/libs/context/performance/fcontext/performance.cpp | 150 | ||||
-rw-r--r-- | src/boost/libs/context/performance/fiber/Jamfile.v2 | 34 | ||||
-rw-r--r-- | src/boost/libs/context/performance/fiber/performance.cpp | 102 |
10 files changed, 689 insertions, 0 deletions
diff --git a/src/boost/libs/context/performance/callcc/Jamfile.v2 b/src/boost/libs/context/performance/callcc/Jamfile.v2 new file mode 100644 index 00000000..5471cb0f --- /dev/null +++ b/src/boost/libs/context/performance/callcc/Jamfile.v2 @@ -0,0 +1,34 @@ + +# Copyright Oliver Kowalke 2009. +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +# For more information, see http://www.boost.org/ + +import common ; +import feature ; +import indirect ; +import modules ; +import os ; +import toolset ; + +project boost/context/performance/callcc + : requirements + <library>/boost/chrono//boost_chrono + <library>/boost/context//boost_context + <library>/boost/program_options//boost_program_options + <toolset>gcc,<segmented-stacks>on:<cxxflags>-fsplit-stack + <toolset>gcc,<segmented-stacks>on:<cxxflags>-DBOOST_USE_SEGMENTED_STACKS + <toolset>clang,<segmented-stacks>on:<cxxflags>-fsplit-stack + <toolset>clang,<segmented-stacks>on:<cxxflags>-DBOOST_USE_SEGMENTED_STACKS + <link>static + <optimization>speed + <threading>multi + <variant>release + <cxxflags>-DBOOST_DISABLE_ASSERTS + ; + +exe performance + : performance.cpp + ; diff --git a/src/boost/libs/context/performance/callcc/performance.cpp b/src/boost/libs/context/performance/callcc/performance.cpp new file mode 100644 index 00000000..21de3c73 --- /dev/null +++ b/src/boost/libs/context/performance/callcc/performance.cpp @@ -0,0 +1,102 @@ + +// Copyright Oliver Kowalke 2009. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include <cstddef> +#include <cstdlib> +#include <iostream> +#include <stdexcept> + +#include <boost/context/continuation.hpp> +#include <boost/cstdint.hpp> +#include <boost/program_options.hpp> + +#include "../clock.hpp" +#include "../cycle.hpp" + +boost::uint64_t jobs = 1000000; + +namespace ctx = boost::context; + +static ctx::continuation foo( ctx::continuation && c) { + while ( true) { + c = c.resume(); + } + return std::move( c); +} + +duration_type measure_time() { + // cache warum-up + ctx::continuation c = ctx::callcc( foo); + c = c.resume(); + + time_point_type start( clock_type::now() ); + for ( std::size_t i = 0; i < jobs; ++i) { + c = c.resume(); + } + duration_type total = clock_type::now() - start; + total -= overhead_clock(); // overhead of measurement + total /= jobs; // loops + total /= 2; // 2x jump_fcontext + + return total; +} + +#ifdef BOOST_CONTEXT_CYCLE +cycle_type measure_cycles() { + // cache warum-up + ctx::fixedsize_stack alloc; + ctx::continuation c = ctx::callcc( std::allocator_arg, alloc, foo); + c = c.resume(); + + cycle_type start( cycles() ); + for ( std::size_t i = 0; i < jobs; ++i) { + c = c.resume(); + } + cycle_type total = cycles() - start; + total -= overhead_cycle(); // overhead of measurement + total /= jobs; // loops + total /= 2; // 2x jump_fcontext + + return total; +} +#endif + +int main( int argc, char * argv[]) { + try { + boost::program_options::options_description desc("allowed options"); + desc.add_options() + ("help", "help message") + ("jobs,j", boost::program_options::value< boost::uint64_t >( & jobs), "jobs to run"); + + boost::program_options::variables_map vm; + boost::program_options::store( + boost::program_options::parse_command_line( + argc, + argv, + desc), + vm); + boost::program_options::notify( vm); + + if ( vm.count("help") ) { + std::cout << desc << std::endl; + return EXIT_SUCCESS; + } + + boost::uint64_t res = measure_time().count(); + std::cout << "continuation: average of " << res << " nano seconds" << std::endl; +#ifdef BOOST_CONTEXT_CYCLE + res = measure_cycles(); + std::cout << "continuation: average of " << res << " cpu cycles" << std::endl; +#endif + + return EXIT_SUCCESS; + } catch ( std::exception const& e) { + std::cerr << "exception: " << e.what() << std::endl; + } catch (...) { + std::cerr << "unhandled exception" << std::endl; + } + return EXIT_FAILURE; +} diff --git a/src/boost/libs/context/performance/clock.hpp b/src/boost/libs/context/performance/clock.hpp new file mode 100644 index 00000000..d8222bb8 --- /dev/null +++ b/src/boost/libs/context/performance/clock.hpp @@ -0,0 +1,45 @@ + +// Copyright Oliver Kowalke 2009. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +#ifndef CLOCK_H +#define CLOCK_H + +#include <algorithm> +#include <cstddef> +#include <numeric> +#include <vector> + +#include <boost/assert.hpp> +#include <boost/chrono.hpp> +#include <boost/cstdint.hpp> + +typedef boost::chrono::high_resolution_clock clock_type; +typedef clock_type::duration duration_type; +typedef clock_type::time_point time_point_type; + +struct clock_overhead +{ + boost::uint64_t operator()() + { + time_point_type start( clock_type::now() ); + return ( clock_type::now() - start).count(); + } +}; + +inline +duration_type overhead_clock() +{ + std::size_t iterations( 10); + std::vector< boost::uint64_t > overhead( iterations, 0); + for ( std::size_t i = 0; i < iterations; ++i) + std::generate( + overhead.begin(), overhead.end(), + clock_overhead() ); + BOOST_ASSERT( overhead.begin() != overhead.end() ); + return duration_type( std::accumulate( overhead.begin(), overhead.end(), 0) / iterations); +} + +#endif // CLOCK_H diff --git a/src/boost/libs/context/performance/cycle.hpp b/src/boost/libs/context/performance/cycle.hpp new file mode 100644 index 00000000..c26c8598 --- /dev/null +++ b/src/boost/libs/context/performance/cycle.hpp @@ -0,0 +1,26 @@ + +// Copyright Oliver Kowalke 2009. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef CYCLE_H +#define CYCLE_H + +// x86_64 +// test x86_64 before i386 because icc might +// define __i686__ for x86_64 too +#if defined(__x86_64__) || defined(__x86_64) \ + || defined(__amd64__) || defined(__amd64) \ + || defined(_M_X64) || defined(_M_AMD64) +# include "cycle_x86-64.hpp" +// i386 +#elif defined(i386) || defined(__i386__) || defined(__i386) \ + || defined(__i486__) || defined(__i586__) || defined(__i686__) \ + || defined(__X86__) || defined(_X86_) || defined(__THW_INTEL__) \ + || defined(__I86__) || defined(__INTEL__) || defined(__IA32__) \ + || defined(_M_IX86) || defined(_I86_) +# include "cycle_i386.hpp" +#endif + +#endif // CYCLE_H diff --git a/src/boost/libs/context/performance/cycle_i386.hpp b/src/boost/libs/context/performance/cycle_i386.hpp new file mode 100644 index 00000000..a3eb7039 --- /dev/null +++ b/src/boost/libs/context/performance/cycle_i386.hpp @@ -0,0 +1,83 @@ + +// Copyright Oliver Kowalke 2009. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef CYCLE_I386_H +#define CYCLE_I386_H + +#include <algorithm> +#include <numeric> +#include <cstddef> +#include <vector> + +#include <boost/assert.hpp> +#include <boost/bind.hpp> +#include <boost/cstdint.hpp> + +#define BOOST_CONTEXT_CYCLE + +typedef boost::uint64_t cycle_type; + +#if _MSC_VER +inline +cycle_type cycles() +{ + cycle_type c; + __asm { + cpuid + rdtsc + mov dword ptr [c + 0], eax + mov dword ptr [c + 4], edx + } + return c; +} +#elif defined(__GNUC__) || \ + defined(__INTEL_COMPILER) || defined(__ICC) || defined(_ECC) || defined(__ICL) +inline +cycle_type cycles() +{ + boost::uint32_t lo, hi; + + __asm__ __volatile__ ( + "xorl %%eax, %%eax\n" + "cpuid\n" + ::: "%eax", "%ebx", "%ecx", "%edx" + ); + __asm__ __volatile__ ("rdtsc" : "=a" (lo), "=d" (hi) ); + __asm__ __volatile__ ( + "xorl %%eax, %%eax\n" + "cpuid\n" + ::: "%eax", "%ebx", "%ecx", "%edx" + ); + + return ( cycle_type)hi << 32 | lo; +} +#else +# error "this compiler is not supported" +#endif + +struct cycle_overhead +{ + cycle_type operator()() + { + cycle_type start( cycles() ); + return cycles() - start; + } +}; + +inline +cycle_type overhead_cycle() +{ + std::size_t iterations( 10); + std::vector< cycle_type > overhead( iterations, 0); + for ( std::size_t i( 0); i < iterations; ++i) + std::generate( + overhead.begin(), overhead.end(), + cycle_overhead() ); + BOOST_ASSERT( overhead.begin() != overhead.end() ); + return std::accumulate( overhead.begin(), overhead.end(), 0) / iterations; +} + +#endif // CYCLE_I386_H diff --git a/src/boost/libs/context/performance/cycle_x86-64.hpp b/src/boost/libs/context/performance/cycle_x86-64.hpp new file mode 100644 index 00000000..fae0226c --- /dev/null +++ b/src/boost/libs/context/performance/cycle_x86-64.hpp @@ -0,0 +1,79 @@ + +// Copyright Oliver Kowalke 2009. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef CYCLE_X86_64_H +#define CYCLE_X86_64_H + +#include <algorithm> +#include <numeric> +#include <cstddef> +#include <vector> + +#include <boost/assert.hpp> +#include <boost/bind.hpp> +#include <boost/cstdint.hpp> + +#define BOOST_CONTEXT_CYCLE + +typedef boost::uint64_t cycle_type; + +#if _MSC_VER >= 1400 +# include <intrin.h> +# pragma intrinsic(__rdtsc) +inline +cycle_type cycles() +{ return __rdtsc(); } +#elif defined(__INTEL_COMPILER) || defined(__ICC) || defined(_ECC) || defined(__ICL) +inline +cycle_type cycles() +{ return __rdtsc(); } +#elif defined(__GNUC__) || defined(__SUNPRO_C) +inline +cycle_type cycles() +{ + boost::uint32_t lo, hi; + + __asm__ __volatile__ ( + "xorl %%eax, %%eax\n" + "cpuid\n" + ::: "%rax", "%rbx", "%rcx", "%rdx" + ); + __asm__ __volatile__ ("rdtsc" : "=a" (lo), "=d" (hi) ); + __asm__ __volatile__ ( + "xorl %%eax, %%eax\n" + "cpuid\n" + ::: "%rax", "%rbx", "%rcx", "%rdx" + ); + + return ( cycle_type)hi << 32 | lo; +} +#else +# error "this compiler is not supported" +#endif + +struct cycle_overhead +{ + cycle_type operator()() + { + cycle_type start( cycles() ); + return cycles() - start; + } +}; + +inline +cycle_type overhead_cycle() +{ + std::size_t iterations( 10); + std::vector< cycle_type > overhead( iterations, 0); + for ( std::size_t i( 0); i < iterations; ++i) + std::generate( + overhead.begin(), overhead.end(), + cycle_overhead() ); + BOOST_ASSERT( overhead.begin() != overhead.end() ); + return std::accumulate( overhead.begin(), overhead.end(), 0) / iterations; +} + +#endif // CYCLE_X86_64_H diff --git a/src/boost/libs/context/performance/fcontext/Jamfile.v2 b/src/boost/libs/context/performance/fcontext/Jamfile.v2 new file mode 100644 index 00000000..eeb2a5d2 --- /dev/null +++ b/src/boost/libs/context/performance/fcontext/Jamfile.v2 @@ -0,0 +1,34 @@ + +# Copyright Oliver Kowalke 2009. +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +# For more information, see http://www.boost.org/ + +import common ; +import feature ; +import indirect ; +import modules ; +import os ; +import toolset ; + +project boost/context/performance/fcontext + : requirements + <library>/boost/chrono//boost_chrono + <library>/boost/context//boost_context + <library>/boost/program_options//boost_program_options + <toolset>gcc,<segmented-stacks>on:<cxxflags>-fsplit-stack + <toolset>gcc,<segmented-stacks>on:<cxxflags>-DBOOST_USE_SEGMENTED_STACKS + <toolset>clang,<segmented-stacks>on:<cxxflags>-fsplit-stack + <toolset>clang,<segmented-stacks>on:<cxxflags>-DBOOST_USE_SEGMENTED_STACKS + <link>static + <optimization>speed + <threading>multi + <variant>release + <cxxflags>-DBOOST_DISABLE_ASSERTS + ; + +exe performance + : performance.cpp + ; diff --git a/src/boost/libs/context/performance/fcontext/performance.cpp b/src/boost/libs/context/performance/fcontext/performance.cpp new file mode 100644 index 00000000..ed271dcc --- /dev/null +++ b/src/boost/libs/context/performance/fcontext/performance.cpp @@ -0,0 +1,150 @@ + +// Copyright Oliver Kowalke 2009. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include <cstddef> +#include <cstdlib> +#include <iostream> +#include <stdexcept> + +#include <boost/context/detail/fcontext.hpp> +#include <boost/cstdint.hpp> +#include <boost/program_options.hpp> + +#include "../clock.hpp" +#include "../cycle.hpp" + +template< std::size_t Max, std::size_t Default, std::size_t Min > +class simple_stack_allocator +{ +public: + static std::size_t maximum_stacksize() + { return Max; } + + static std::size_t default_stacksize() + { return Default; } + + static std::size_t minimum_stacksize() + { return Min; } + + void * allocate( std::size_t size) const + { + BOOST_ASSERT( minimum_stacksize() <= size); + BOOST_ASSERT( maximum_stacksize() >= size); + + void * limit = std::malloc( size); + if ( ! limit) throw std::bad_alloc(); + + return static_cast< char * >( limit) + size; + } + + void deallocate( void * vp, std::size_t size) const + { + BOOST_ASSERT( vp); + BOOST_ASSERT( minimum_stacksize() <= size); + BOOST_ASSERT( maximum_stacksize() >= size); + + void * limit = static_cast< char * >( vp) - size; + std::free( limit); + } +}; + +typedef simple_stack_allocator< + 8 * 1024 * 1024, 64 * 1024, 8 * 1024 + > stack_allocator; + +boost::uint64_t jobs = 1000000; + +static void foo( boost::context::detail::transfer_t t_) { + boost::context::detail::transfer_t t = t_; + while ( true) { + t = boost::context::detail::jump_fcontext( t.fctx, 0); + } +} + +duration_type measure_time_fc() { + stack_allocator stack_alloc; + boost::context::detail::fcontext_t ctx = boost::context::detail::make_fcontext( + stack_alloc.allocate( stack_allocator::default_stacksize() ), + stack_allocator::default_stacksize(), + foo); + + // cache warum-up + boost::context::detail::transfer_t t = boost::context::detail::jump_fcontext( ctx, 0); + + time_point_type start( clock_type::now() ); + for ( std::size_t i = 0; i < jobs; ++i) { + t = boost::context::detail::jump_fcontext( t.fctx, 0); + } + duration_type total = clock_type::now() - start; + total -= overhead_clock(); // overhead of measurement + total /= jobs; // loops + total /= 2; // 2x jump_fcontext + + return total; +} + +#ifdef BOOST_CONTEXT_CYCLE +cycle_type measure_cycles_fc() { + stack_allocator stack_alloc; + boost::context::detail::fcontext_t ctx = boost::context::detail::make_fcontext( + stack_alloc.allocate( stack_allocator::default_stacksize() ), + stack_allocator::default_stacksize(), + foo); + + // cache warum-up + boost::context::detail::transfer_t t = boost::context::detail::jump_fcontext( ctx, 0); + + cycle_type start( cycles() ); + for ( std::size_t i = 0; i < jobs; ++i) { + t = boost::context::detail::jump_fcontext( t.fctx, 0); + } + cycle_type total = cycles() - start; + total -= overhead_cycle(); // overhead of measurement + total /= jobs; // loops + total /= 2; // 2x jump_fcontext + + return total; +} +#endif + +int main( int argc, char * argv[]) +{ + try + { + boost::program_options::options_description desc("allowed options"); + desc.add_options() + ("help", "help message") + ("jobs,j", boost::program_options::value< boost::uint64_t >( & jobs), "jobs to run"); + + boost::program_options::variables_map vm; + boost::program_options::store( + boost::program_options::parse_command_line( + argc, + argv, + desc), + vm); + boost::program_options::notify( vm); + + if ( vm.count("help") ) { + std::cout << desc << std::endl; + return EXIT_SUCCESS; + } + + boost::uint64_t res = measure_time_fc().count(); + std::cout << "fcontext_t: average of " << res << " nano seconds" << std::endl; +#ifdef BOOST_CONTEXT_CYCLE + res = measure_cycles_fc(); + std::cout << "fcontext_t: average of " << res << " cpu cycles" << std::endl; +#endif + + return EXIT_SUCCESS; + } + catch ( std::exception const& e) + { std::cerr << "exception: " << e.what() << std::endl; } + catch (...) + { std::cerr << "unhandled exception" << std::endl; } + return EXIT_FAILURE; +} diff --git a/src/boost/libs/context/performance/fiber/Jamfile.v2 b/src/boost/libs/context/performance/fiber/Jamfile.v2 new file mode 100644 index 00000000..5e9f54f3 --- /dev/null +++ b/src/boost/libs/context/performance/fiber/Jamfile.v2 @@ -0,0 +1,34 @@ + +# Copyright Oliver Kowalke 2009. +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +# For more information, see http://www.boost.org/ + +import common ; +import feature ; +import indirect ; +import modules ; +import os ; +import toolset ; + +project boost/context/performance/fiber + : requirements + <library>/boost/chrono//boost_chrono + <library>/boost/context//boost_context + <library>/boost/program_options//boost_program_options + <toolset>gcc,<segmented-stacks>on:<cxxflags>-fsplit-stack + <toolset>gcc,<segmented-stacks>on:<cxxflags>-DBOOST_USE_SEGMENTED_STACKS + <toolset>clang,<segmented-stacks>on:<cxxflags>-fsplit-stack + <toolset>clang,<segmented-stacks>on:<cxxflags>-DBOOST_USE_SEGMENTED_STACKS + <link>static + <optimization>speed + <threading>multi + <variant>release + <cxxflags>-DBOOST_DISABLE_ASSERTS + ; + +exe performance + : performance.cpp + ; diff --git a/src/boost/libs/context/performance/fiber/performance.cpp b/src/boost/libs/context/performance/fiber/performance.cpp new file mode 100644 index 00000000..e49deecd --- /dev/null +++ b/src/boost/libs/context/performance/fiber/performance.cpp @@ -0,0 +1,102 @@ + +// Copyright Oliver Kowalke 2009. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include <cstddef> +#include <cstdlib> +#include <iostream> +#include <stdexcept> + +#include <boost/context/fiber.hpp> +#include <boost/cstdint.hpp> +#include <boost/program_options.hpp> + +#include "../clock.hpp" +#include "../cycle.hpp" + +boost::uint64_t jobs = 1000000; + +namespace ctx = boost::context; + +static ctx::fiber foo( ctx::fiber && f) { + while ( true) { + f = std::move( f).resume(); + } + return ctx::fiber{}; +} + +duration_type measure_time() { + // cache warum-up + ctx::fiber f{ foo }; + f = std::move( f).resume(); + + time_point_type start( clock_type::now() ); + for ( std::size_t i = 0; i < jobs; ++i) { + f = std::move( f).resume(); + } + duration_type total = clock_type::now() - start; + total -= overhead_clock(); // overhead of measurement + total /= jobs; // loops + total /= 2; // 2x jump_fcontext + + return total; +} + +#ifdef BOOST_CONTEXT_CYCLE +cycle_type measure_cycles() { + // cache warum-up + ctx::fixedsize_stack alloc; + ctx::fiber f{ std::allocator_arg, alloc, foo }; + f = std::move( f).resume(); + + cycle_type start( cycles() ); + for ( std::size_t i = 0; i < jobs; ++i) { + f = std::move( f).resume(); + } + cycle_type total = cycles() - start; + total -= overhead_cycle(); // overhead of measurement + total /= jobs; // loops + total /= 2; // 2x jump_fcontext + + return total; +} +#endif + +int main( int argc, char * argv[]) { + try { + boost::program_options::options_description desc("allowed options"); + desc.add_options() + ("help", "help message") + ("jobs,j", boost::program_options::value< boost::uint64_t >( & jobs), "jobs to run"); + + boost::program_options::variables_map vm; + boost::program_options::store( + boost::program_options::parse_command_line( + argc, + argv, + desc), + vm); + boost::program_options::notify( vm); + + if ( vm.count("help") ) { + std::cout << desc << std::endl; + return EXIT_SUCCESS; + } + + boost::uint64_t res = measure_time().count(); + std::cout << "fiber: average of " << res << " nano seconds" << std::endl; +#ifdef BOOST_CONTEXT_CYCLE + res = measure_cycles(); + std::cout << "fiber: average of " << res << " cpu cycles" << std::endl; +#endif + + return EXIT_SUCCESS; + } catch ( std::exception const& e) { + std::cerr << "exception: " << e.what() << std::endl; + } catch (...) { + std::cerr << "unhandled exception" << std::endl; + } + return EXIT_FAILURE; +} |