138a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden/*
238a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden * Copyright (C) 2010 The Android Open Source Project
338a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden *
438a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden * Licensed under the Apache License, Version 2.0 (the "License");
538a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden * you may not use this file except in compliance with the License.
638a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden * You may obtain a copy of the License at
738a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden *
838a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden *      http://www.apache.org/licenses/LICENSE-2.0
938a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden *
1038a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden * Unless required by applicable law or agreed to in writing, software
1138a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden * distributed under the License is distributed on an "AS IS" BASIS,
1238a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1338a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden * See the License for the specific language governing permissions and
1438a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden * limitations under the License.
1538a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden */
1638a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden
1738a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden/*
1838a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden * This provides a handful of correctness and speed tests on our atomic
1938a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden * operations.
2038a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden *
2138a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden * This doesn't really belong here, but we currently lack a better place
2238a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden * for it, so this will do for now.
2338a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden */
2438a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden#include "Dalvik.h"
2538a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden
2638a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden#include <stdlib.h>
2738a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden#include <stdio.h>
2838a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden#include <pthread.h>
2938a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden#include <unistd.h>
3038a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden#include <cutils/atomic.h>
3138a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden#ifdef __arm__
3238a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden# include <machine/cpu-features.h>
3338a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden#endif
3438a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden
3538a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden#define USE_ATOMIC      1
3638a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden#define THREAD_COUNT    10
3738a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden#define ITERATION_COUNT 500000
3838a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden
3938a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden#ifdef HAVE_ANDROID_OS
4038a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden/*#define TEST_BIONIC 1*/
4138a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden#endif
4238a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden
4338a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden
4438a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden#ifdef TEST_BIONIC
4538a17866b31e0b6dee320f32a8644e358583ab23Andy McFaddenextern int __atomic_cmpxchg(int old, int _new, volatile int *ptr);
4638a17866b31e0b6dee320f32a8644e358583ab23Andy McFaddenextern int __atomic_swap(int _new, volatile int *ptr);
4738a17866b31e0b6dee320f32a8644e358583ab23Andy McFaddenextern int __atomic_dec(volatile int *ptr);
4838a17866b31e0b6dee320f32a8644e358583ab23Andy McFaddenextern int __atomic_inc(volatile int *ptr);
4938a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden#endif
5038a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden
5138a17866b31e0b6dee320f32a8644e358583ab23Andy McFaddenstatic pthread_mutex_t waitLock = PTHREAD_MUTEX_INITIALIZER;
5238a17866b31e0b6dee320f32a8644e358583ab23Andy McFaddenstatic pthread_cond_t waitCond = PTHREAD_COND_INITIALIZER;
5338a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden
5438a17866b31e0b6dee320f32a8644e358583ab23Andy McFaddenstatic volatile int threadsStarted = 0;
5538a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden
5638a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden/* results */
5738a17866b31e0b6dee320f32a8644e358583ab23Andy McFaddenstatic int incTest = 0;
5838a17866b31e0b6dee320f32a8644e358583ab23Andy McFaddenstatic int decTest = 0;
5938a17866b31e0b6dee320f32a8644e358583ab23Andy McFaddenstatic int addTest = 0;
6038a17866b31e0b6dee320f32a8644e358583ab23Andy McFaddenstatic int andTest = 0;
6138a17866b31e0b6dee320f32a8644e358583ab23Andy McFaddenstatic int orTest = 0;
6238a17866b31e0b6dee320f32a8644e358583ab23Andy McFaddenstatic int casTest = 0;
6338a17866b31e0b6dee320f32a8644e358583ab23Andy McFaddenstatic int failingCasTest = 0;
6438a17866b31e0b6dee320f32a8644e358583ab23Andy McFaddenstatic int64_t wideCasTest = 0x6600000077000000LL;
6538a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden
6638a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden/*
6738a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden * Get a relative time value.
6838a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden */
691e1433e78f560a01744e870c19c162ab88df9dc1Carl Shapirostatic int64_t getRelativeTimeNsec()
7038a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden{
7138a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden#define HAVE_POSIX_CLOCKS
7238a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden#ifdef HAVE_POSIX_CLOCKS
7338a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    struct timespec now;
7438a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    clock_gettime(CLOCK_MONOTONIC, &now);
7538a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    return (int64_t) now.tv_sec*1000000000LL + now.tv_nsec;
7638a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden#else
7738a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    struct timeval now;
7838a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    gettimeofday(&now, NULL);
7938a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    return (int64_t) now.tv_sec*1000000000LL + now.tv_usec * 1000LL;
8038a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden#endif
8138a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden}
8238a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden
8338a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden
8438a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden/*
8538a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden * Non-atomic implementations, for comparison.
8638a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden *
8738a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden * If these get inlined the compiler may figure out what we're up to and
8838a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden * completely elide the operations.
8938a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden */
901e1433e78f560a01744e870c19c162ab88df9dc1Carl Shapirostatic void incr() __attribute__((noinline));
911e1433e78f560a01744e870c19c162ab88df9dc1Carl Shapirostatic void decr() __attribute__((noinline));
9238a17866b31e0b6dee320f32a8644e358583ab23Andy McFaddenstatic void add(int addVal) __attribute__((noinline));
9338a17866b31e0b6dee320f32a8644e358583ab23Andy McFaddenstatic int compareAndSwap(int oldVal, int newVal, int* addr) __attribute__((noinline));
9438a17866b31e0b6dee320f32a8644e358583ab23Andy McFaddenstatic int compareAndSwapWide(int64_t oldVal, int64_t newVal, int64_t* addr) __attribute__((noinline));
9538a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden
961e1433e78f560a01744e870c19c162ab88df9dc1Carl Shapirostatic void incr()
9738a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden{
9838a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    incTest++;
9938a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden}
1001e1433e78f560a01744e870c19c162ab88df9dc1Carl Shapirostatic void decr()
10138a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden{
10238a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    decTest--;
10338a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden}
10438a17866b31e0b6dee320f32a8644e358583ab23Andy McFaddenstatic void add(int32_t addVal)
10538a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden{
10638a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    addTest += addVal;
10738a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden}
10838a17866b31e0b6dee320f32a8644e358583ab23Andy McFaddenstatic int compareAndSwap(int32_t oldVal, int32_t newVal, int32_t* addr)
10938a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden{
11038a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    if (*addr == oldVal) {
11138a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden        *addr = newVal;
11238a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden        return 0;
11338a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    }
11438a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    return 1;
11538a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden}
11638a17866b31e0b6dee320f32a8644e358583ab23Andy McFaddenstatic int compareAndSwapWide(int64_t oldVal, int64_t newVal, int64_t* addr)
11738a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden{
11838a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    if (*addr == oldVal) {
11938a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden        *addr = newVal;
12038a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden        return 0;
12138a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    }
12238a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    return 1;
12338a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden}
12438a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden
12538a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden/*
12638a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden * Exercise several of the atomic ops.
12738a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden */
12838a17866b31e0b6dee320f32a8644e358583ab23Andy McFaddenstatic void doAtomicTest(int num)
12938a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden{
13038a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    int addVal = (num & 0x01) + 1;
13138a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden
13238a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    int i;
13338a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    for (i = 0; i < ITERATION_COUNT; i++) {
13438a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden        if (USE_ATOMIC) {
13538a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden            android_atomic_inc(&incTest);
13638a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden            android_atomic_dec(&decTest);
13738a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden            android_atomic_add(addVal, &addTest);
13838a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden
13938a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden            int val;
14038a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden            do {
14138a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden                val = casTest;
14238a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden            } while (android_atomic_release_cas(val, val+3, &casTest) != 0);
14338a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden            do {
14438a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden                val = casTest;
14538a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden            } while (android_atomic_acquire_cas(val, val-1, &casTest) != 0);
14638a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden
14738a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden            int64_t wval;
14838a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden            do {
14938a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden                wval = dvmQuasiAtomicRead64(&wideCasTest);
15038a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden            } while (dvmQuasiAtomicCas64(wval,
15138a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden                        wval + 0x0000002000000001LL, &wideCasTest) != 0);
15238a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden            do {
15338a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden                wval = dvmQuasiAtomicRead64(&wideCasTest);
15438a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden            } while (dvmQuasiAtomicCas64(wval,
15538a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden                        wval - 0x0000002000000001LL, &wideCasTest) != 0);
15638a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden        } else {
15738a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden            incr();
15838a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden            decr();
15938a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden            add(addVal);
16038a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden
16138a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden            int val;
16238a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden            do {
16338a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden                val = casTest;
16438a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden            } while (compareAndSwap(val, val+3, &casTest) != 0);
16538a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden            do {
16638a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden                val = casTest;
16738a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden            } while (compareAndSwap(val, val-1, &casTest) != 0);
16838a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden
16938a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden            int64_t wval;
17038a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden            do {
17138a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden                wval = wideCasTest;
17238a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden            } while (compareAndSwapWide(wval,
17338a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden                        wval + 0x0000002000000001LL, &wideCasTest) != 0);
17438a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden            do {
17538a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden                wval = wideCasTest;
17638a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden            } while (compareAndSwapWide(wval,
17738a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden                        wval - 0x0000002000000001LL, &wideCasTest) != 0);
17838a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden        }
17938a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    }
18038a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden}
18138a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden
18238a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden/*
18338a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden * Entry point for multi-thread test.
18438a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden */
18538a17866b31e0b6dee320f32a8644e358583ab23Andy McFaddenstatic void* atomicTest(void* arg)
18638a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden{
18738a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    pthread_mutex_lock(&waitLock);
18838a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    threadsStarted++;
18938a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    pthread_cond_wait(&waitCond, &waitLock);
19038a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    pthread_mutex_unlock(&waitLock);
19138a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden
19238a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    doAtomicTest((int) arg);
19338a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden
19438a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    return NULL;
19538a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden}
19638a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden
19738a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden/* lifted from a VM test */
19838a17866b31e0b6dee320f32a8644e358583ab23Andy McFaddenstatic int64_t testAtomicSpeedSub(int repeatCount)
19938a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden{
20038a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    static int value = 7;
20138a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    int* valuePtr = &value;
20238a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    int64_t start, end;
20338a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    int i;
20438a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden
20538a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    start = getRelativeTimeNsec();
20638a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden
20738a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    for (i = repeatCount / 10; i != 0; i--) {
20838a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden        if (USE_ATOMIC) {
20938a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden            // succeed 10x
2101e1433e78f560a01744e870c19c162ab88df9dc1Carl Shapiro            android_atomic_release_cas(7, 7, valuePtr);
2111e1433e78f560a01744e870c19c162ab88df9dc1Carl Shapiro            android_atomic_release_cas(7, 7, valuePtr);
2121e1433e78f560a01744e870c19c162ab88df9dc1Carl Shapiro            android_atomic_release_cas(7, 7, valuePtr);
2131e1433e78f560a01744e870c19c162ab88df9dc1Carl Shapiro            android_atomic_release_cas(7, 7, valuePtr);
2141e1433e78f560a01744e870c19c162ab88df9dc1Carl Shapiro            android_atomic_release_cas(7, 7, valuePtr);
2151e1433e78f560a01744e870c19c162ab88df9dc1Carl Shapiro            android_atomic_release_cas(7, 7, valuePtr);
2161e1433e78f560a01744e870c19c162ab88df9dc1Carl Shapiro            android_atomic_release_cas(7, 7, valuePtr);
2171e1433e78f560a01744e870c19c162ab88df9dc1Carl Shapiro            android_atomic_release_cas(7, 7, valuePtr);
2181e1433e78f560a01744e870c19c162ab88df9dc1Carl Shapiro            android_atomic_release_cas(7, 7, valuePtr);
2191e1433e78f560a01744e870c19c162ab88df9dc1Carl Shapiro            android_atomic_release_cas(7, 7, valuePtr);
22038a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden        } else {
22138a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden            // succeed 10x
22238a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden            compareAndSwap(7, 7, valuePtr);
22338a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden            compareAndSwap(7, 7, valuePtr);
22438a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden            compareAndSwap(7, 7, valuePtr);
22538a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden            compareAndSwap(7, 7, valuePtr);
22638a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden            compareAndSwap(7, 7, valuePtr);
22738a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden            compareAndSwap(7, 7, valuePtr);
22838a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden            compareAndSwap(7, 7, valuePtr);
22938a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden            compareAndSwap(7, 7, valuePtr);
23038a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden            compareAndSwap(7, 7, valuePtr);
23138a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden            compareAndSwap(7, 7, valuePtr);
23238a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden        }
23338a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    }
23438a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden
23538a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    end = getRelativeTimeNsec();
23638a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden
23738a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    dvmFprintf(stdout, ".");
23838a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    fflush(stdout);
23938a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    return end - start;
24038a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden}
24138a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden
2421e1433e78f560a01744e870c19c162ab88df9dc1Carl Shapirostatic void testAtomicSpeed()
24338a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden{
24438a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    static const int kIterations = 10;
24538a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    static const int kRepeatCount = 5 * 1000 * 1000;
24638a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    static const int kDelay = 50 * 1000;
24738a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    int64_t results[kIterations];
24838a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    int i;
24938a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden
25038a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    for (i = 0; i < kIterations; i++) {
25138a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden        results[i] = testAtomicSpeedSub(kRepeatCount);
25238a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden        usleep(kDelay);
25338a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    }
25438a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden
25538a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    dvmFprintf(stdout, "\n");
25638a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    dvmFprintf(stdout, "%s speed test results (%d per iteration):\n",
25738a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden        USE_ATOMIC ? "Atomic" : "Non-atomic", kRepeatCount);
25838a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    for (i = 0; i < kIterations; i++) {
25938a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden        dvmFprintf(stdout,
26038a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden            " %2d: %.3fns\n", i, (double) results[i] / kRepeatCount);
26138a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    }
26238a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden}
26338a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden
26438a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden/*
26538a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden * Start tests, show results.
26638a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden */
2671e1433e78f560a01744e870c19c162ab88df9dc1Carl Shapirobool dvmTestAtomicSpeed()
26838a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden{
26938a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    pthread_t threads[THREAD_COUNT];
27038a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    void *(*startRoutine)(void*) = atomicTest;
27138a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    int64_t startWhen, endWhen;
27238a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden
27338a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden#if defined(__ARM_ARCH__)
27438a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    dvmFprintf(stdout, "__ARM_ARCH__ is %d\n", __ARM_ARCH__);
27538a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden#endif
27638a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden#if defined(ANDROID_SMP)
27738a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    dvmFprintf(stdout, "ANDROID_SMP is %d\n", ANDROID_SMP);
27838a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden#endif
27938a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    dvmFprintf(stdout, "Creating threads\n");
28038a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden
28138a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    int i;
28238a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    for (i = 0; i < THREAD_COUNT; i++) {
28338a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden        void* arg = (void*) i;
28438a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden        if (pthread_create(&threads[i], NULL, startRoutine, arg) != 0) {
28538a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden            dvmFprintf(stderr, "thread create failed\n");
28638a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden        }
28738a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    }
28838a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden
28938a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    /* wait for all the threads to reach the starting line */
29038a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    while (1) {
29138a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden        pthread_mutex_lock(&waitLock);
29238a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden        if (threadsStarted == THREAD_COUNT) {
29338a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden            dvmFprintf(stdout, "Starting test\n");
29438a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden            startWhen = getRelativeTimeNsec();
29538a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden            pthread_cond_broadcast(&waitCond);
29638a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden            pthread_mutex_unlock(&waitLock);
29738a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden            break;
29838a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden        }
29938a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden        pthread_mutex_unlock(&waitLock);
30038a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden        usleep(100000);
30138a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    }
30238a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden
30338a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    for (i = 0; i < THREAD_COUNT; i++) {
30438a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden        void* retval;
30538a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden        if (pthread_join(threads[i], &retval) != 0) {
30638a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden            dvmFprintf(stderr, "thread join (%d) failed\n", i);
30738a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden        }
30838a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    }
30938a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden
31038a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    endWhen = getRelativeTimeNsec();
31138a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    dvmFprintf(stdout, "All threads stopped, time is %.6fms\n",
31238a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden        (endWhen - startWhen) / 1000000.0);
31338a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden
31438a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    /*
31538a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden     * Show results; expecting:
31638a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden     *
31738a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden     * incTest = 5000000
31838a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden     * decTest = -5000000
31938a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden     * addTest = 7500000
32038a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden     * casTest = 10000000
32138a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden     * wideCasTest = 0x6600000077000000
32238a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden     */
32338a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    dvmFprintf(stdout, "incTest = %d\n", incTest);
32438a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    dvmFprintf(stdout, "decTest = %d\n", decTest);
32538a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    dvmFprintf(stdout, "addTest = %d\n", addTest);
32638a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    dvmFprintf(stdout, "casTest = %d\n", casTest);
32738a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    dvmFprintf(stdout, "wideCasTest = 0x%llx\n", wideCasTest);
32838a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden
32938a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    /* do again, serially (SMP check) */
33038a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    startWhen = getRelativeTimeNsec();
33138a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    for (i = 0; i < THREAD_COUNT; i++) {
33238a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden        doAtomicTest(i);
33338a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    }
33438a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    endWhen = getRelativeTimeNsec();
33538a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    dvmFprintf(stdout, "Same iterations done serially: time is %.6fms\n",
33638a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden        (endWhen - startWhen) / 1000000.0);
33738a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden
33838a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    /*
33938a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden     * Hard to do a meaningful thrash test on these, so just do a simple
34038a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden     * function test.
34138a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden     */
34238a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    andTest = 0xffd7fa96;
34338a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    orTest = 0x122221ff;
34438a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    android_atomic_and(0xfffdaf96, &andTest);
34538a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    android_atomic_or(0xdeaaeb00, &orTest);
34638a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    if (android_atomic_release_cas(failingCasTest+1, failingCasTest-1,
34738a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden            &failingCasTest) == 0)
34838a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden        dvmFprintf(stdout, "failing test did not fail!\n");
34938a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden
350291c84f60853d30e1c0d79dd08c5e5164f588e26Dan Bornstein    dvmFprintf(stdout, "andTest = %#x\n", andTest);
351291c84f60853d30e1c0d79dd08c5e5164f588e26Dan Bornstein    dvmFprintf(stdout, "orTest = %#x\n", orTest);
35238a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    dvmFprintf(stdout, "failingCasTest = %d\n", failingCasTest);
35338a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden
35438a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden#ifdef TEST_BIONIC
35538a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    /*
35638a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden     * Quick function test on the bionic ops.
35738a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden     */
35838a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    int prev;
35938a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    int tester = 7;
36038a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    prev = __atomic_inc(&tester);
36138a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    __atomic_inc(&tester);
36238a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    __atomic_inc(&tester);
36338a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    dvmFprintf(stdout, "bionic 3 inc: %d -> %d\n", prev, tester);
36438a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    prev = __atomic_dec(&tester);
36538a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    __atomic_dec(&tester);
36638a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    __atomic_dec(&tester);
36738a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    dvmFprintf(stdout, "bionic 3 dec: %d -> %d\n", prev, tester);
36838a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    prev = __atomic_swap(27, &tester);
36938a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    dvmFprintf(stdout, "bionic swap: %d -> %d\n", prev, tester);
37038a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    int swapok = __atomic_cmpxchg(27, 72, &tester);
37138a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    dvmFprintf(stdout, "bionic cmpxchg: %d (%d)\n", tester, swapok);
37238a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden#endif
37338a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden
37438a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    testAtomicSpeed();
37538a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden
37638a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    return 0;
37738a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden}
378