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 int swapTest = 0;
6538a17866b31e0b6dee320f32a8644e358583ab23Andy McFaddenstatic int64_t wideCasTest = 0x6600000077000000LL;
6638a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden
6738a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden/*
6838a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden * Get a relative time value.
6938a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden */
7038a17866b31e0b6dee320f32a8644e358583ab23Andy McFaddenstatic int64_t getRelativeTimeNsec(void)
7138a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden{
7238a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden#define HAVE_POSIX_CLOCKS
7338a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden#ifdef HAVE_POSIX_CLOCKS
7438a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    struct timespec now;
7538a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    clock_gettime(CLOCK_MONOTONIC, &now);
7638a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    return (int64_t) now.tv_sec*1000000000LL + now.tv_nsec;
7738a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden#else
7838a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    struct timeval now;
7938a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    gettimeofday(&now, NULL);
8038a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    return (int64_t) now.tv_sec*1000000000LL + now.tv_usec * 1000LL;
8138a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden#endif
8238a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden}
8338a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden
8438a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden
8538a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden/*
8638a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden * Non-atomic implementations, for comparison.
8738a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden *
8838a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden * If these get inlined the compiler may figure out what we're up to and
8938a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden * completely elide the operations.
9038a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden */
9138a17866b31e0b6dee320f32a8644e358583ab23Andy McFaddenstatic void incr(void) __attribute__((noinline));
9238a17866b31e0b6dee320f32a8644e358583ab23Andy McFaddenstatic void decr(void) __attribute__((noinline));
9338a17866b31e0b6dee320f32a8644e358583ab23Andy McFaddenstatic void add(int addVal) __attribute__((noinline));
9438a17866b31e0b6dee320f32a8644e358583ab23Andy McFaddenstatic int compareAndSwap(int oldVal, int newVal, int* addr) __attribute__((noinline));
9538a17866b31e0b6dee320f32a8644e358583ab23Andy McFaddenstatic int compareAndSwapWide(int64_t oldVal, int64_t newVal, int64_t* addr) __attribute__((noinline));
9638a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden
9738a17866b31e0b6dee320f32a8644e358583ab23Andy McFaddenstatic void incr(void)
9838a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden{
9938a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    incTest++;
10038a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden}
10138a17866b31e0b6dee320f32a8644e358583ab23Andy McFaddenstatic void decr(void)
10238a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden{
10338a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    decTest--;
10438a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden}
10538a17866b31e0b6dee320f32a8644e358583ab23Andy McFaddenstatic void add(int32_t addVal)
10638a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden{
10738a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    addTest += addVal;
10838a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden}
10938a17866b31e0b6dee320f32a8644e358583ab23Andy McFaddenstatic int compareAndSwap(int32_t oldVal, int32_t newVal, int32_t* addr)
11038a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden{
11138a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    if (*addr == oldVal) {
11238a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden        *addr = newVal;
11338a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden        return 0;
11438a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    }
11538a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    return 1;
11638a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden}
11738a17866b31e0b6dee320f32a8644e358583ab23Andy McFaddenstatic int compareAndSwapWide(int64_t oldVal, int64_t newVal, int64_t* addr)
11838a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden{
11938a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    if (*addr == oldVal) {
12038a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden        *addr = newVal;
12138a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden        return 0;
12238a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    }
12338a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    return 1;
12438a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden}
12538a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden
12638a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden/*
12738a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden * Exercise several of the atomic ops.
12838a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden */
12938a17866b31e0b6dee320f32a8644e358583ab23Andy McFaddenstatic void doAtomicTest(int num)
13038a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden{
13138a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    int addVal = (num & 0x01) + 1;
13238a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden
13338a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    int i;
13438a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    for (i = 0; i < ITERATION_COUNT; i++) {
13538a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden        if (USE_ATOMIC) {
13638a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden            android_atomic_inc(&incTest);
13738a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden            android_atomic_dec(&decTest);
13838a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden            android_atomic_add(addVal, &addTest);
13938a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden
14038a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden            int val;
14138a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden            do {
14238a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden                val = casTest;
14338a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden            } while (android_atomic_release_cas(val, val+3, &casTest) != 0);
14438a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden            do {
14538a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden                val = casTest;
14638a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden            } while (android_atomic_acquire_cas(val, val-1, &casTest) != 0);
14738a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden
14838a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden            int64_t wval;
14938a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden            do {
15038a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden                wval = dvmQuasiAtomicRead64(&wideCasTest);
15138a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden            } while (dvmQuasiAtomicCas64(wval,
15238a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden                        wval + 0x0000002000000001LL, &wideCasTest) != 0);
15338a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden            do {
15438a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden                wval = dvmQuasiAtomicRead64(&wideCasTest);
15538a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden            } while (dvmQuasiAtomicCas64(wval,
15638a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden                        wval - 0x0000002000000001LL, &wideCasTest) != 0);
15738a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden        } else {
15838a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden            incr();
15938a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden            decr();
16038a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden            add(addVal);
16138a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden
16238a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden            int val;
16338a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden            do {
16438a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden                val = casTest;
16538a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden            } while (compareAndSwap(val, val+3, &casTest) != 0);
16638a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden            do {
16738a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden                val = casTest;
16838a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden            } while (compareAndSwap(val, val-1, &casTest) != 0);
16938a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden
17038a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden            int64_t wval;
17138a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden            do {
17238a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden                wval = wideCasTest;
17338a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden            } while (compareAndSwapWide(wval,
17438a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden                        wval + 0x0000002000000001LL, &wideCasTest) != 0);
17538a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden            do {
17638a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden                wval = wideCasTest;
17738a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden            } while (compareAndSwapWide(wval,
17838a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden                        wval - 0x0000002000000001LL, &wideCasTest) != 0);
17938a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden        }
18038a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    }
18138a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden}
18238a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden
18338a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden/*
18438a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden * Entry point for multi-thread test.
18538a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden */
18638a17866b31e0b6dee320f32a8644e358583ab23Andy McFaddenstatic void* atomicTest(void* arg)
18738a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden{
18838a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    pthread_mutex_lock(&waitLock);
18938a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    threadsStarted++;
19038a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    pthread_cond_wait(&waitCond, &waitLock);
19138a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    pthread_mutex_unlock(&waitLock);
19238a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden
19338a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    doAtomicTest((int) arg);
19438a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden
19538a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    return NULL;
19638a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden}
19738a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden
19838a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden/* lifted from a VM test */
19938a17866b31e0b6dee320f32a8644e358583ab23Andy McFaddenstatic int64_t testAtomicSpeedSub(int repeatCount)
20038a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden{
20138a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    static int value = 7;
20238a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    int* valuePtr = &value;
20338a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    int64_t start, end;
20438a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    int i;
20538a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden
20638a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    start = getRelativeTimeNsec();
20738a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden
20838a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    for (i = repeatCount / 10; i != 0; i--) {
20938a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden        if (USE_ATOMIC) {
21038a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden            // succeed 10x
21138a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden            (void) android_atomic_release_cas(7, 7, valuePtr);
21238a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden            (void) android_atomic_release_cas(7, 7, valuePtr);
21338a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden            (void) android_atomic_release_cas(7, 7, valuePtr);
21438a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden            (void) android_atomic_release_cas(7, 7, valuePtr);
21538a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden            (void) android_atomic_release_cas(7, 7, valuePtr);
21638a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden            (void) android_atomic_release_cas(7, 7, valuePtr);
21738a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden            (void) android_atomic_release_cas(7, 7, valuePtr);
21838a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden            (void) android_atomic_release_cas(7, 7, valuePtr);
21938a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden            (void) android_atomic_release_cas(7, 7, valuePtr);
22038a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden            (void) android_atomic_release_cas(7, 7, valuePtr);
22138a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden        } else {
22238a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden            // succeed 10x
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            compareAndSwap(7, 7, valuePtr);
23338a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden        }
23438a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    }
23538a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden
23638a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    end = getRelativeTimeNsec();
23738a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden
23838a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    dvmFprintf(stdout, ".");
23938a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    fflush(stdout);
24038a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    return end - start;
24138a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden}
24238a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden
24338a17866b31e0b6dee320f32a8644e358583ab23Andy McFaddenstatic void testAtomicSpeed(void)
24438a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden{
24538a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    static const int kIterations = 10;
24638a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    static const int kRepeatCount = 5 * 1000 * 1000;
24738a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    static const int kDelay = 50 * 1000;
24838a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    int64_t results[kIterations];
24938a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    int i;
25038a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden
25138a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    for (i = 0; i < kIterations; i++) {
25238a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden        results[i] = testAtomicSpeedSub(kRepeatCount);
25338a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden        usleep(kDelay);
25438a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    }
25538a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden
25638a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    dvmFprintf(stdout, "\n");
25738a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    dvmFprintf(stdout, "%s speed test results (%d per iteration):\n",
25838a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden        USE_ATOMIC ? "Atomic" : "Non-atomic", kRepeatCount);
25938a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    for (i = 0; i < kIterations; i++) {
26038a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden        dvmFprintf(stdout,
26138a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden            " %2d: %.3fns\n", i, (double) results[i] / kRepeatCount);
26238a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    }
26338a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden}
26438a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden
26538a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden/*
26638a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden * Start tests, show results.
26738a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden */
26838a17866b31e0b6dee320f32a8644e358583ab23Andy McFaddenbool dvmTestAtomicSpeed(void)
26938a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden{
27038a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    pthread_t threads[THREAD_COUNT];
27138a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    void *(*startRoutine)(void*) = atomicTest;
27238a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    int64_t startWhen, endWhen;
27338a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden
27438a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden#if defined(__ARM_ARCH__)
27538a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    dvmFprintf(stdout, "__ARM_ARCH__ is %d\n", __ARM_ARCH__);
27638a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden#endif
27738a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden#if defined(ANDROID_SMP)
27838a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    dvmFprintf(stdout, "ANDROID_SMP is %d\n", ANDROID_SMP);
27938a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden#endif
28038a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    dvmFprintf(stdout, "Creating threads\n");
28138a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden
28238a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    int i;
28338a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    for (i = 0; i < THREAD_COUNT; i++) {
28438a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden        void* arg = (void*) i;
28538a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden        if (pthread_create(&threads[i], NULL, startRoutine, arg) != 0) {
28638a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden            dvmFprintf(stderr, "thread create failed\n");
28738a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden        }
28838a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    }
28938a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden
29038a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    /* wait for all the threads to reach the starting line */
29138a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    while (1) {
29238a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden        pthread_mutex_lock(&waitLock);
29338a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden        if (threadsStarted == THREAD_COUNT) {
29438a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden            dvmFprintf(stdout, "Starting test\n");
29538a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden            startWhen = getRelativeTimeNsec();
29638a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden            pthread_cond_broadcast(&waitCond);
29738a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden            pthread_mutex_unlock(&waitLock);
29838a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden            break;
29938a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden        }
30038a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden        pthread_mutex_unlock(&waitLock);
30138a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden        usleep(100000);
30238a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    }
30338a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden
30438a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    for (i = 0; i < THREAD_COUNT; i++) {
30538a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden        void* retval;
30638a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden        if (pthread_join(threads[i], &retval) != 0) {
30738a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden            dvmFprintf(stderr, "thread join (%d) failed\n", i);
30838a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden        }
30938a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    }
31038a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden
31138a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    endWhen = getRelativeTimeNsec();
31238a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    dvmFprintf(stdout, "All threads stopped, time is %.6fms\n",
31338a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden        (endWhen - startWhen) / 1000000.0);
31438a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden
31538a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    /*
31638a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden     * Show results; expecting:
31738a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden     *
31838a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden     * incTest = 5000000
31938a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden     * decTest = -5000000
32038a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden     * addTest = 7500000
32138a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden     * casTest = 10000000
32238a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden     * wideCasTest = 0x6600000077000000
32338a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden     */
32438a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    dvmFprintf(stdout, "incTest = %d\n", incTest);
32538a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    dvmFprintf(stdout, "decTest = %d\n", decTest);
32638a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    dvmFprintf(stdout, "addTest = %d\n", addTest);
32738a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    dvmFprintf(stdout, "casTest = %d\n", casTest);
32838a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    dvmFprintf(stdout, "wideCasTest = 0x%llx\n", wideCasTest);
32938a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden
33038a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    /* do again, serially (SMP check) */
33138a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    startWhen = getRelativeTimeNsec();
33238a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    for (i = 0; i < THREAD_COUNT; i++) {
33338a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden        doAtomicTest(i);
33438a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    }
33538a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    endWhen = getRelativeTimeNsec();
33638a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    dvmFprintf(stdout, "Same iterations done serially: time is %.6fms\n",
33738a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden        (endWhen - startWhen) / 1000000.0);
33838a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden
33938a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    /*
34038a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden     * Hard to do a meaningful thrash test on these, so just do a simple
34138a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden     * function test.
34238a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden     */
34338a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    andTest = 0xffd7fa96;
34438a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    orTest = 0x122221ff;
34538a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    swapTest = 0x11111111;
34638a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    android_atomic_and(0xfffdaf96, &andTest);
34738a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    android_atomic_or(0xdeaaeb00, &orTest);
34863e53deb445448f0131a73f64313c7d965c8487eCarl Shapiro    int oldSwap = android_atomic_swap(0x22222222, &swapTest);
34963e53deb445448f0131a73f64313c7d965c8487eCarl Shapiro    int oldSwap2 = android_atomic_swap(0x33333333, &swapTest);
35038a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    if (android_atomic_release_cas(failingCasTest+1, failingCasTest-1,
35138a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden            &failingCasTest) == 0)
35238a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden        dvmFprintf(stdout, "failing test did not fail!\n");
35338a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden
35438a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    dvmFprintf(stdout, "andTest = 0x%x\n", andTest);
35538a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    dvmFprintf(stdout, "orTest = 0x%x\n", orTest);
356453e05f3847e8c7170291df04225d41abbecd4f9Carl Shapiro    dvmFprintf(stdout, "swapTest = 0x%x -> 0x%x\n", oldSwap, oldSwap2);
357453e05f3847e8c7170291df04225d41abbecd4f9Carl Shapiro    dvmFprintf(stdout, "swapTest = 0x%x -> 0x%x\n", oldSwap2, swapTest);
35838a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    dvmFprintf(stdout, "failingCasTest = %d\n", failingCasTest);
35938a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden
36038a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden#ifdef TEST_BIONIC
36138a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    /*
36238a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden     * Quick function test on the bionic ops.
36338a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden     */
36438a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    int prev;
36538a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    int tester = 7;
36638a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    prev = __atomic_inc(&tester);
36738a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    __atomic_inc(&tester);
36838a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    __atomic_inc(&tester);
36938a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    dvmFprintf(stdout, "bionic 3 inc: %d -> %d\n", prev, tester);
37038a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    prev = __atomic_dec(&tester);
37138a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    __atomic_dec(&tester);
37238a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    __atomic_dec(&tester);
37338a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    dvmFprintf(stdout, "bionic 3 dec: %d -> %d\n", prev, tester);
37438a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    prev = __atomic_swap(27, &tester);
37538a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    dvmFprintf(stdout, "bionic swap: %d -> %d\n", prev, tester);
37638a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    int swapok = __atomic_cmpxchg(27, 72, &tester);
37738a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    dvmFprintf(stdout, "bionic cmpxchg: %d (%d)\n", tester, swapok);
37838a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden#endif
37938a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden
38038a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    testAtomicSpeed();
38138a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden
38238a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden    return 0;
38338a17866b31e0b6dee320f32a8644e358583ab23Andy McFadden}
384