/*
 * Copyright (C) by Argonne National Laboratory
 *     See COPYRIGHT in top-level directory
 */

#ifndef MPL_TIMER_LINUX86_CYCLE_H_INCLUDED
#define MPL_TIMER_LINUX86_CYCLE_H_INCLUDED

static inline int MPL_wtime(MPL_time_t * timeval)
{
/* The rdtsc instruction is not a "serializing" instruction, so the
   processor is free to reorder it.  In order to get more accurate
   timing numbers with rdtsc, we need to put a serializing
   instruction, like cpuid, before rdtsc.  X86_64 architectures have
   the rdtscp instruction which is synchronizing, we use this when we
   can. */
#ifdef MPL_LINUX86_CYCLE_RDTSCP
    unsigned long long lower, upper, extra;
    __asm__ __volatile__("rdtscp\n":"=a"(lower), "=d"(upper), "=c"(extra));
    *timeval = (upper << 32) + lower;

#elif defined(MPL_LINUX86_CYCLE_CPUID_RDTSC64)
    unsigned long long lower, upper;
    __asm__ __volatile__("cpuid ; rdtsc":"=a"(lower), "=d"(upper)::"ebx", "ecx");
    *timeval = (upper << 32) + lower;

#elif  defined(MPL_LINUX86_CYCLE_CPUID_RDTSC32)
    __asm__ __volatile__("cpuid ; rdtsc":"=A"(*timeval)::"ebx", "ecx");

#elif defined(MPL_LINUX86_CYCLE_RDTSC)
/* The configure test using cpuid must have failed, try just rdtsc by itself */
    __asm__ __volatile__("rdtsc":"=A"(*timeval));

#else
#error Dont know which Linux timer to use
#endif

    return MPL_SUCCESS;
}

#endif /* MPL_TIMER_LINUX86_CYCLE_H_INCLUDED */
