diff options
author | Michael Brown | 2014-04-23 18:43:18 +0200 |
---|---|---|
committer | Michael Brown | 2014-04-28 00:14:43 +0200 |
commit | e5f6a9be384f6adc2b50ffdb8781e81327b790aa (patch) | |
tree | 42efc59b490b68891abd81a5cc11ac938c3848c2 /src/tests | |
parent | [libc] Add flsll() (diff) | |
download | ipxe-e5f6a9be384f6adc2b50ffdb8781e81327b790aa.tar.gz ipxe-e5f6a9be384f6adc2b50ffdb8781e81327b790aa.tar.xz ipxe-e5f6a9be384f6adc2b50ffdb8781e81327b790aa.zip |
[profile] Add generic profiling infrastructure
Signed-off-by: Michael Brown <mcb30@ipxe.org>
Diffstat (limited to 'src/tests')
-rw-r--r-- | src/tests/cbc_test.c | 20 | ||||
-rw-r--r-- | src/tests/digest_test.c | 27 | ||||
-rw-r--r-- | src/tests/memcpy_test.c | 24 | ||||
-rw-r--r-- | src/tests/profile_test.c | 140 | ||||
-rw-r--r-- | src/tests/tcpip_test.c | 21 | ||||
-rw-r--r-- | src/tests/tests.c | 1 |
6 files changed, 204 insertions, 29 deletions
diff --git a/src/tests/cbc_test.c b/src/tests/cbc_test.c index ada991b2..cb0f7bde 100644 --- a/src/tests/cbc_test.c +++ b/src/tests/cbc_test.c @@ -36,6 +36,9 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include <ipxe/profile.h> #include "cbc_test.h" +/** Number of sample iterations for profiling */ +#define PROFILE_COUNT 16 + /** * Test CBC encryption * @@ -115,8 +118,7 @@ static unsigned long cbc_cost ( struct cipher_algorithm *cipher, uint8_t key[key_len]; uint8_t iv[cipher->blocksize]; uint8_t ctx[cipher->ctxsize]; - union profiler profiler; - unsigned long long elapsed; + struct profiler profiler; unsigned long cost; unsigned int i; int rc; @@ -135,13 +137,17 @@ static unsigned long cbc_cost ( struct cipher_algorithm *cipher, assert ( rc == 0 ); cipher_setiv ( cipher, ctx, iv ); - /* Time operation */ - profile ( &profiler ); - op ( cipher, ctx, random, random, sizeof ( random ) ); - elapsed = profile ( &profiler ); + /* Profile cipher operation */ + memset ( &profiler, 0, sizeof ( profiler ) ); + for ( i = 0 ; i < PROFILE_COUNT ; i++ ) { + profile_start ( &profiler ); + op ( cipher, ctx, random, random, sizeof ( random ) ); + profile_stop ( &profiler ); + } /* Round to nearest whole number of cycles per byte */ - cost = ( ( elapsed + ( sizeof ( random ) / 2 ) ) / sizeof ( random ) ); + cost = ( ( profile_mean ( &profiler ) + ( sizeof ( random ) / 2 ) ) / + sizeof ( random ) ); return cost; } diff --git a/src/tests/digest_test.c b/src/tests/digest_test.c index 6428cc72..4df26c09 100644 --- a/src/tests/digest_test.c +++ b/src/tests/digest_test.c @@ -25,12 +25,18 @@ FILE_LICENCE ( GPL2_OR_LATER ); * */ +/* Forcibly enable assertions */ +#undef NDEBUG + #include <stdlib.h> #include <string.h> #include <ipxe/crypto.h> #include <ipxe/profile.h> #include "digest_test.h" +/** Number of sample iterations for profiling */ +#define PROFILE_COUNT 16 + /** * Test digest algorithm * @@ -81,8 +87,7 @@ unsigned long digest_cost ( struct digest_algorithm *digest ) { static uint8_t random[8192]; /* Too large for stack */ uint8_t ctx[digest->ctxsize]; uint8_t out[digest->digestsize]; - union profiler profiler; - unsigned long long elapsed; + struct profiler profiler; unsigned long cost; unsigned int i; @@ -91,15 +96,19 @@ unsigned long digest_cost ( struct digest_algorithm *digest ) { for ( i = 0 ; i < sizeof ( random ) ; i++ ) random[i] = rand(); - /* Time digest calculation */ - profile ( &profiler ); - digest_init ( digest, ctx ); - digest_update ( digest, ctx, random, sizeof ( random ) ); - digest_final ( digest, ctx, out ); - elapsed = profile ( &profiler ); + /* Profile digest calculation */ + memset ( &profiler, 0, sizeof ( profiler ) ); + for ( i = 0 ; i < PROFILE_COUNT ; i++ ) { + profile_start ( &profiler ); + digest_init ( digest, ctx ); + digest_update ( digest, ctx, random, sizeof ( random ) ); + digest_final ( digest, ctx, out ); + profile_stop ( &profiler ); + } /* Round to nearest whole number of cycles per byte */ - cost = ( ( elapsed + ( sizeof ( random ) / 2 ) ) / sizeof ( random ) ); + cost = ( ( profile_mean ( &profiler ) + ( sizeof ( random ) / 2 ) ) / + sizeof ( random ) ); return cost; } diff --git a/src/tests/memcpy_test.c b/src/tests/memcpy_test.c index b405a9f2..f1e5503a 100644 --- a/src/tests/memcpy_test.c +++ b/src/tests/memcpy_test.c @@ -34,6 +34,9 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include <ipxe/test.h> #include <ipxe/profile.h> +/** Number of sample iterations for profiling */ +#define PROFILE_COUNT 16 + /* Provide global functions to allow inspection of generated code */ void memcpy_0 ( void *dest, void *src ) { memcpy ( dest, src, 0 ); } @@ -120,10 +123,10 @@ __attribute__ (( noinline )) void * memcpy_var ( void *dest, const void *src, */ static void memcpy_test_speed ( unsigned int dest_offset, unsigned int src_offset, size_t len ) { + struct profiler profiler; uint8_t *dest; uint8_t *src; unsigned int i; - unsigned long elapsed; /* Allocate blocks */ dest = malloc ( len + dest_offset ); @@ -135,21 +138,26 @@ static void memcpy_test_speed ( unsigned int dest_offset, for ( i = 0 ; i < len ; i++ ) src[ src_offset + i ] = random(); - /* Perform memcpy() */ - simple_profile(); + /* Check correctness of copied data */ memcpy ( ( dest + dest_offset ), ( src + src_offset ), len ); - elapsed = simple_profile(); - - /* Check copied data */ ok ( memcmp ( ( dest + dest_offset ), ( src + src_offset ), len ) == 0 ); + /* Profile memcpy() */ + memset ( &profiler, 0, sizeof ( profiler ) ); + for ( i = 0 ; i < PROFILE_COUNT ; i++ ) { + profile_start ( &profiler ); + memcpy ( ( dest + dest_offset ), ( src + src_offset ), len ); + profile_stop ( &profiler ); + } + /* Free blocks */ free ( dest ); free ( src ); - DBG ( "MEMCPY copied %zd bytes (+%d => +%d) in %ld ticks\n", - len, src_offset, dest_offset, elapsed ); + DBG ( "MEMCPY copied %zd bytes (+%d => +%d) in %ld +/- %ld ticks\n", + len, src_offset, dest_offset, profile_mean ( &profiler ), + profile_stddev ( &profiler ) ); } /** diff --git a/src/tests/profile_test.c b/src/tests/profile_test.c new file mode 100644 index 00000000..9d682bf2 --- /dev/null +++ b/src/tests/profile_test.c @@ -0,0 +1,140 @@ +/* + * Copyright (C) 2014 Michael Brown <mbrown@fensystems.co.uk>. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +/** @file + * + * Profiling self-tests + * + */ + +/* Forcibly enable assertions */ +#undef NDEBUG + +#include <string.h> +#include <assert.h> +#include <ipxe/test.h> +#include <ipxe/profile.h> + +/** A profiling test */ +struct profile_test { + /** Sample values */ + const unsigned long *samples; + /** Number of samples */ + unsigned int count; + /** Expected mean sample value */ + unsigned long mean; + /** Expected standard deviation */ + unsigned long stddev; +}; + +/** Define inline data */ +#define DATA(...) { __VA_ARGS__ } + +/** Define a profiling test */ +#define PROFILE_TEST( name, MEAN, STDDEV, SAMPLES ) \ + static const unsigned long name ## _samples[] = SAMPLES; \ + static struct profile_test name = { \ + .samples = name ## _samples, \ + .count = ( sizeof ( name ## _samples ) / \ + sizeof ( name ## _samples [0] ) ), \ + .mean = MEAN, \ + .stddev = STDDEV, \ + } + +/** Empty data set */ +PROFILE_TEST ( empty, 0, 0, DATA() ); + +/** Single-element data set (zero) */ +PROFILE_TEST ( zero, 0, 0, DATA ( 0 ) ); + +/** Single-element data set (non-zero) */ +PROFILE_TEST ( single, 42, 0, DATA ( 42 ) ); + +/** Multiple identical element data set */ +PROFILE_TEST ( identical, 69, 0, DATA ( 69, 69, 69, 69, 69, 69, 69 ) ); + +/** Small element data set */ +PROFILE_TEST ( small, 5, 2, DATA ( 3, 5, 9, 4, 3, 2, 5, 7 ) ); + +/** Random data set */ +PROFILE_TEST ( random, 70198, 394, + DATA ( 69772, 70068, 70769, 69653, 70663, 71078, 70101, 70341, + 70215, 69600, 70020, 70456, 70421, 69972, 70267, 69999, + 69972 ) ); + +/** Large-valued random data set */ +PROFILE_TEST ( large, 93533894UL, 25538UL, + DATA ( 93510333UL, 93561169UL, 93492361UL, 93528647UL, + 93557566UL, 93503465UL, 93540126UL, 93549020UL, + 93502307UL, 93527320UL, 93537152UL, 93540125UL, + 93550773UL, 93586731UL, 93521312UL ) ); + +/** + * Report a profiling test result + * + * @v test Profiling test + * @v file Test code file + * @v line Test code line + */ +static void profile_okx ( struct profile_test *test, const char *file, + unsigned int line ) { + struct profiler profiler; + unsigned long mean; + unsigned long stddev; + unsigned int i; + + /* Initialise profiler */ + memset ( &profiler, 0, sizeof ( profiler ) ); + + /* Record sample values */ + for ( i = 0 ; i < test->count ; i++ ) + profile_update ( &profiler, test->samples[i] ); + + /* Check resulting statistics */ + mean = profile_mean ( &profiler ); + stddev = profile_stddev ( &profiler ); + DBGC ( test, "PROFILE calculated mean %ld stddev %ld\n", mean, stddev ); + okx ( mean == test->mean, file, line ); + okx ( stddev == test->stddev, file, line ); +} +#define profile_ok( test ) profile_okx ( test, __FILE__, __LINE__ ) + +/** + * Perform profiling self-tests + * + */ +static void profile_test_exec ( void ) { + + /* Perform profiling tests */ + profile_ok ( &empty ); + profile_ok ( &zero ); + profile_ok ( &single ); + profile_ok ( &identical ); + profile_ok ( &small ); + profile_ok ( &random ); + profile_ok ( &large ); +} + +/** Profiling self-test */ +struct self_test profile_test __self_test = { + .name = "profile", + .exec = profile_test_exec, +}; diff --git a/src/tests/tcpip_test.c b/src/tests/tcpip_test.c index 4ff23e3f..00c88ae3 100644 --- a/src/tests/tcpip_test.c +++ b/src/tests/tcpip_test.c @@ -36,6 +36,9 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include <ipxe/profile.h> #include <ipxe/tcpip.h> +/** Number of sample iterations for profiling */ +#define PROFILE_COUNT 16 + /** A TCP/IP fixed-data test */ struct tcpip_test { /** Data */ @@ -173,10 +176,10 @@ static void tcpip_okx ( struct tcpip_test *test, const char *file, static void tcpip_random_okx ( struct tcpip_random_test *test, const char *file, unsigned int line ) { uint8_t *data = ( tcpip_data + test->offset ); + struct profiler profiler; uint16_t expected; uint16_t generic_sum; uint16_t sum; - unsigned long elapsed; unsigned int i; /* Sanity check */ @@ -194,12 +197,20 @@ static void tcpip_random_okx ( struct tcpip_random_test *test, okx ( generic_sum == expected, file, line ); /* Verify optimised tcpip_continue_chksum() result */ - simple_profile(); sum = tcpip_continue_chksum ( TCPIP_EMPTY_CSUM, data, test->len ); - elapsed = simple_profile(); okx ( sum == expected, file, line ); - DBG ( "TCPIP checksummed %zd bytes (+%zd) in %ld ticks\n", - test->len, test->offset, elapsed ); + + /* Profile optimised calculation */ + memset ( &profiler, 0, sizeof ( profiler ) ); + for ( i = 0 ; i < PROFILE_COUNT ; i++ ) { + profile_start ( &profiler ); + sum = tcpip_continue_chksum ( TCPIP_EMPTY_CSUM, data, + test->len ); + profile_stop ( &profiler ); + } + DBG ( "TCPIP checksummed %zd bytes (+%zd) in %ld +/- %ld ticks\n", + test->len, test->offset, profile_mean ( &profiler ), + profile_stddev ( &profiler ) ); } #define tcpip_random_ok( test ) tcpip_random_okx ( test, __FILE__, __LINE__ ) diff --git a/src/tests/tests.c b/src/tests/tests.c index 8c8c6216..2b4b78c7 100644 --- a/src/tests/tests.c +++ b/src/tests/tests.c @@ -55,3 +55,4 @@ REQUIRE_OBJECT ( deflate_test ); REQUIRE_OBJECT ( png_test ); REQUIRE_OBJECT ( dns_test ); REQUIRE_OBJECT ( uri_test ); +REQUIRE_OBJECT ( profile_test ); |