133cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner/*
233cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner * Copyright (C) 2011 The Android Open Source Project
333cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner * All rights reserved.
433cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner *
533cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner * Redistribution and use in source and binary forms, with or without
633cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner * modification, are permitted provided that the following conditions
733cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner * are met:
833cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner *  * Redistributions of source code must retain the above copyright
933cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner *    notice, this list of conditions and the following disclaimer.
1033cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner *  * Redistributions in binary form must reproduce the above copyright
1133cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner *    notice, this list of conditions and the following disclaimer in
1233cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner *    the documentation and/or other materials provided with the
1333cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner *    distribution.
1433cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner *
1533cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
1633cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
1733cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
1833cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
1933cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
2033cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
2133cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
2233cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
2333cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
2433cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
2533cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2633cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner * SUCH DAMAGE.
2733cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner */
2833cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner
2933cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner/* This program is used to benchmark various pthread operations
3033cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner * Note that we want to be able to build it with GLibc, both on
3133cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner *  a Linux host and an Android device. For example, on ARM, one
3233cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner * can build it manually with:
3333cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner *
3433cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner *     arm-linux-none-gnueabi-gcc -static -o bench_pthread_gnueabi \
3533cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner *           bench_pthread.c -O2 -lpthread -lrt
3633cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner */
3733cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner#define _GNU_SOURCE 1
3833cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner#include <time.h>
3933cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner#include <stdio.h>
4033cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner#include <stdint.h>
4133cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner#include <limits.h>
4233cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner#include <pthread.h>
4333cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner#include <semaphore.h>
4433cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner#include <stdlib.h>
4533cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner#include <unistd.h>
4633cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner
4733cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner#define S(x)  S_(x)
4833cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner#define S_(x) #x
4933cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner
5033cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner#define C(x,y)  C_(x,y)
5133cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner#define C_(x,y) x ## y
5233cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner
5333cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner#ifndef PTHREAD_ERRORCHECK_MUTEX_INITIALIZER
5433cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner#define PTHREAD_ERRORCHECK_MUTEX_INITIALIZER  PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP
5533cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner#endif
5633cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner
5733cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner#ifndef PTHREAD_RECURSIVE_MUTEX_INITIALIZER
5833cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner#define PTHREAD_RECURSIVE_MUTEX_INITIALIZER  PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP
5933cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner#endif
6033cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner
6133cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turnerstatic int64_t now_ns(void)
6233cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner{
6333cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner    struct timespec ts;
6433cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner    /* NOTE: get thread-specific CPU-time clock to ensure
6533cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner     *       we don't measure stuff like kernel thread preemptions
6633cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner     *       that might happen during the benchmark
6733cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner     */
6833cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner    clock_gettime(CLOCK_THREAD_CPUTIME_ID,&ts);
6933cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner    return ts.tv_sec*1000000000LL + ts.tv_nsec;
7033cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner}
7133cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner
7233cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner#define SUBCOUNT   10000
7333cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner#define MAX_STATS  1000000
7433cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner
7533cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner/* Maximum time we'll wait for a single bench run */
7633cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner#define MAX_WAIT_MS  1000
7733cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner
7833cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turnerstatic int64_t  stats[MAX_STATS];
7933cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner
8033cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turnerstatic int
8133cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turnercompare_stats(const void* a, const void* b)
8233cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner{
8333cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner    uint64_t sa = *(const uint64_t*)a;
8433cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner    uint64_t sb = *(const uint64_t*)b;
8533cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner    if (sa < sb)
8633cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner        return -1;
8733cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner    if (sa > sb)
8833cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner        return +1;
8933cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner    else
9033cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner        return 0;
9133cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner}
9233cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner
9333cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turnerstatic void
9433cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turnerfilter_stats(int count, const char* statement)
9533cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner{
9633cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner    int64_t  min, max, avg, median;
9733cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner
9833cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner    /* sort the array in increasing order */
9933cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner    qsort(stats, count, sizeof(stats[0]), compare_stats);
10033cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner
10133cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner    /* trim 10% to remove outliers */
10233cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner    int min_index = count*0.05;
10333cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner    int max_index = count - min_index;
10433cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner    if (max_index >= count)
10533cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner        max_index = count-1;
10633cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner
10733cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner    count = (max_index - min_index)+1;
10833cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner
10933cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner    /* the median is the center item */
11033cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner    median = stats[(min_index+max_index)/2];
11133cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner
11233cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner    /* the minimum is the first, the max the last */
11333cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner    min = stats[min_index];
11433cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner    max = stats[max_index];
11533cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner
11633cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner    /* compute the average */
11733cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner    int nn;
11833cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner    int64_t  total = 0;
11933cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner    for (nn = min_index; nn <= max_index; nn++) {
12033cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner        total += stats[nn];
12133cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner    }
12233cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner
12333cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner    printf("BENCH: %5.1f %5.1f %5.1f, %s\n",
12433cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner           min*1./SUBCOUNT,
12533cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner           max*1./SUBCOUNT,
12633cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner           median*1./SUBCOUNT,
12733cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner           statement);
12833cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner    if (0) {
12933cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner        for (nn = min_index; nn <= max_index; nn++) {
13033cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner            printf(" %lld", (long long)stats[nn]);
13133cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner        }
13233cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner        printf("\n");
13333cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner    }
13433cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner}
13533cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner
13633cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner#define BENCH_COUNT(stmnt,total) do { \
13733cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner        int64_t  count = total; \
13833cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner        int      num_stats = 0; \
13933cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner        int64_t  bench_start = now_ns(); \
14033cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner        while (num_stats < MAX_STATS && count >= SUBCOUNT) { \
14133cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner            int      tries = SUBCOUNT; \
14233cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner            int64_t  sub_start = now_ns(); \
14333cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner            count -= tries; \
14433cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner            for ( ; tries > 0; tries-- ) {\
14533cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner                stmnt;\
14633cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner            }\
14733cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner            int64_t  sub_end = now_ns(); \
14833cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner            stats[num_stats++] = sub_end - sub_start; \
14933cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner            if (sub_end - bench_start >= MAX_WAIT_MS*1e6) \
15033cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner                break; \
15133cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner        } \
15233cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner        filter_stats(num_stats, #stmnt); \
15333cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner    } while (0)
15433cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner
15533cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner#define DEFAULT_COUNT 10000000
15633cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner
15733cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner#define BENCH(stmnt) BENCH_COUNT(stmnt,DEFAULT_COUNT)
15833cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner
15933cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner/* Will be called by pthread_once() for benchmarking */
16033cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turnerstatic void _dummy_init(void)
16133cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner{
16233cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner    /* nothing */
16333cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner}
16433cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner
16533cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner/* Used when creating the key */
16633cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turnerstatic void key_destroy(void* param)
16733cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner{
16833cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner    /* nothing */
16933cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner}
17033cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner
17133cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turnerint main(void)
17233cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner{
17333cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner    pthread_once_t  once = PTHREAD_ONCE_INIT;
17433cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner    pthread_once(&once, _dummy_init);
17533cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner
17633cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner    pthread_key_t   key;
17733cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner    pthread_key_create(&key, key_destroy);
17833cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner    pthread_setspecific(key, (void*)(int)100);
17933cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner
18033cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner    BENCH(getpid());
18133cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner    BENCH(pthread_self());
18233cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner    BENCH(pthread_getspecific(key));
18333cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner    BENCH(pthread_once(&once, _dummy_init));
18433cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner
18533cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner    pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
18633cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner    BENCH(pthread_mutex_lock(&mutex); pthread_mutex_unlock(&mutex));
18733cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner
18833cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner    pthread_mutex_t errorcheck_mutex = PTHREAD_ERRORCHECK_MUTEX_INITIALIZER;
18933cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner    BENCH(pthread_mutex_lock(&errorcheck_mutex); pthread_mutex_unlock(&errorcheck_mutex));
19033cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner
19133cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner    pthread_mutex_t recursive_mutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER;
19233cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner    BENCH(pthread_mutex_lock(&recursive_mutex); pthread_mutex_unlock(&recursive_mutex));
19333cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner
19433cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner	/* TODO: Benchmark pshared mutexes */
19533cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner
19633cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner    sem_t semaphore;
19733cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner    int dummy;
19833cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner    sem_init(&semaphore, 1, 1);
19933cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner    BENCH(sem_getvalue(&semaphore,&dummy));
20033cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner    BENCH(sem_wait(&semaphore); sem_post(&semaphore));
20133cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner    return 0;
20233cf0fee9523f7c796a71f42d2031a532351bb88David 'Digit' Turner}
203