i = 0
child.sendline(test_name)
- index = child.expect(["Start timer stress tests \(30 seconds\)",
+ index = child.expect(["Start timer stress tests \(20 seconds\)",
"Test Failed",
pexpect.TIMEOUT], timeout = 10)
elif index == 2:
return -1, "Fail [Timeout]"
- index = child.expect(["Start timer basic tests \(30 seconds\)",
+ index = child.expect(["Start timer basic tests \(20 seconds\)",
"Test Failed",
pexpect.TIMEOUT], timeout = 40)
#include <rte_tailq.h>
#include <rte_eal.h>
#include <rte_timer.h>
+#include <rte_cycles.h>
+#include <rte_log.h>
#include <rte_string_fns.h>
#include "test.h"
+#define RTE_LOGTYPE_APP RTE_LOGTYPE_USER1
+
const char *prgname; /* to be set to argv[0] */
#ifndef RTE_EXEC_ENV_BAREMETAL
return do_recursive_call();
#endif
+#ifdef RTE_LIBEAL_USE_HPET
+ if (rte_eal_hpet_init(1) < 0)
+#endif
+ RTE_LOG(INFO, APP,
+ "HPET is not enabled, using TSC as default timer\n");
+
+
+
cl = cmdline_stdin_new(main_ctx, "RTE>>");
if (cl == NULL) {
return -1;
{
unsigned i;
uint64_t start_cycles, cycles, prev_cycles;
- uint64_t hz = rte_get_hpet_hz();
+ uint64_t hz = rte_get_timer_hz();
uint64_t max_inc = (hz / 100); /* 10 ms max between 2 reads */
/* check that the timer is always incrementing */
- start_cycles = rte_get_hpet_cycles();
+ start_cycles = rte_get_timer_cycles();
prev_cycles = start_cycles;
for (i=0; i<N; i++) {
- cycles = rte_get_hpet_cycles();
+ cycles = rte_get_timer_cycles();
if ((uint64_t)(cycles - prev_cycles) > max_inc) {
printf("increment too high or going backwards\n");
return -1;
}
/* check that waiting 1 second is precise */
- prev_cycles = rte_get_hpet_cycles();
+ prev_cycles = rte_get_timer_cycles();
rte_delay_us(1000000);
- cycles = rte_get_hpet_cycles();
+ cycles = rte_get_timer_cycles();
if ((uint64_t)(cycles - prev_cycles) > (hz + max_inc)) {
printf("delay_us is not accurate: too long\n");
unsigned int i;
void *obj = NULL;
uint64_t start_cycles, end_cycles;
- uint64_t duration = rte_get_hpet_hz() * 8;
+ uint64_t duration = rte_get_timer_hz() * 8;
- start_cycles = rte_get_hpet_cycles();
+ start_cycles = rte_get_timer_cycles();
while (1) {
- end_cycles = rte_get_hpet_cycles();
+ end_cycles = rte_get_timer_cycles();
/* duration uses up, stop producing */
if (start_cycles + duration < end_cycles)
break;
unsigned int i;
void * obj;
uint64_t start_cycles, end_cycles;
- uint64_t duration = rte_get_hpet_hz() * 5;
+ uint64_t duration = rte_get_timer_hz() * 5;
- start_cycles = rte_get_hpet_cycles();
+ start_cycles = rte_get_timer_cycles();
while (1) {
- end_cycles = rte_get_hpet_cycles();
+ end_cycles = rte_get_timer_cycles();
/* duration uses up, stop consuming */
if (start_cycles + duration < end_cycles)
break;
unsigned lcore_id = rte_lcore_id();
int ret;
uint64_t start_cycles, end_cycles;
- uint64_t time_diff = 0, hz = rte_get_hpet_hz();
+ uint64_t time_diff = 0, hz = rte_get_timer_hz();
/* n_get_bulk and n_put_bulk must be divisors of n_keep */
if (((n_keep / n_get_bulk) * n_get_bulk) != n_keep)
if (lcore_id != rte_get_master_lcore())
while (rte_atomic32_read(&synchro) == 0);
- start_cycles = rte_get_hpet_cycles();
+ start_cycles = rte_get_timer_cycles();
while (time_diff/hz < TIME_S) {
for (i = 0; likely(i < (N/n_keep)); i++) {
idx += n_put_bulk;
}
}
- end_cycles = rte_get_hpet_cycles();
+ end_cycles = rte_get_timer_cycles();
time_diff = end_cycles - start_cycles;
stats[lcore_id].enq_count += N;
}
static int
check_live_watermark_change(__attribute__((unused)) void *dummy)
{
- uint64_t hz = rte_get_hpet_hz();
+ uint64_t hz = rte_get_timer_hz();
void *obj_table[MAX_BULK];
unsigned watermark, watermark_old = 16;
uint64_t cur_time, end_time;
/* init the object table */
memset(obj_table, 0, sizeof(obj_table));
- end_time = rte_get_hpet_cycles() + (hz * 2);
+ end_time = rte_get_timer_cycles() + (hz * 2);
/* check that bulk and watermark are 4 and 32 (respectively) */
while (diff >= 0) {
}
}
- cur_time = rte_get_hpet_cycles();
+ cur_time = rte_get_timer_cycles();
diff = end_time - cur_time;
}
load_loop_fn(void *func_param)
{
uint64_t time_diff = 0, begin;
- uint64_t hz = rte_get_hpet_hz();
+ uint64_t hz = rte_get_timer_hz();
uint64_t lcount = 0;
const int use_lock = *(int*)func_param;
const unsigned lcore = rte_lcore_id();
if (lcore != rte_get_master_lcore())
while (rte_atomic32_read(&synchro) == 0);
- begin = rte_get_hpet_cycles();
+ begin = rte_get_timer_cycles();
while (time_diff / hz < TIME_S) {
if (use_lock)
rte_spinlock_lock(&lk);
rte_spinlock_unlock(&lk);
/* delay to make lock duty cycle slighlty realistic */
rte_delay_us(1);
- time_diff = rte_get_hpet_cycles() - begin;
+ time_diff = rte_get_timer_cycles() - begin;
}
lock_count[lcore] = lcount;
return 0;
#include <stdint.h>
#include <inttypes.h>
#include <sys/queue.h>
+#include <math.h>
#include <cmdline_parse.h>
#include "test.h"
-#define TEST_DURATION_S 30 /* in seconds */
+#define TEST_DURATION_S 20 /* in seconds */
#define NB_TIMER 4
#define RTE_LOGTYPE_TESTTIMER RTE_LOGTYPE_USER3
static void timer_basic_cb(struct rte_timer *tim, void *arg);
static void
-mytimer_reset(struct mytimerinfo *timinfo, unsigned ticks,
+mytimer_reset(struct mytimerinfo *timinfo, uint64_t ticks,
enum rte_timer_type type, unsigned tim_lcore,
rte_timer_cb_t fct)
{
{
long r;
unsigned lcore_id = rte_lcore_id();
- uint64_t hz = rte_get_hpet_hz();
+ uint64_t hz = rte_get_timer_hz();
if (rte_timer_pending(tim))
return;
static int
timer_stress_main_loop(__attribute__((unused)) void *arg)
{
- uint64_t hz = rte_get_hpet_hz();
+ uint64_t hz = rte_get_timer_hz();
unsigned lcore_id = rte_lcore_id();
uint64_t cur_time;
int64_t diff = 0;
else if ((r & 0xff) == 1) {
rte_timer_stop_sync(&mytiminfo[0].tim);
}
- cur_time = rte_get_hpet_cycles();
+ cur_time = rte_get_timer_cycles();
diff = end_time - cur_time;
}
timer_basic_cb(struct rte_timer *tim, void *arg)
{
struct mytimerinfo *timinfo = arg;
- uint64_t hz = rte_get_hpet_hz();
+ uint64_t hz = rte_get_timer_hz();
unsigned lcore_id = rte_lcore_id();
- uint64_t cur_time = rte_get_hpet_cycles();
+ uint64_t cur_time = rte_get_timer_cycles();
if (rte_timer_pending(tim))
return;
static int
timer_basic_main_loop(__attribute__((unused)) void *arg)
{
- uint64_t hz = rte_get_hpet_hz();
+ uint64_t hz = rte_get_timer_hz();
unsigned lcore_id = rte_lcore_id();
uint64_t cur_time;
int64_t diff = 0;
* (3 us = 6000 cycles at 2 Ghz) */
rte_delay_us(3);
- cur_time = rte_get_hpet_cycles();
+ cur_time = rte_get_timer_cycles();
diff = end_time - cur_time;
}
RTE_LOG(INFO, TESTTIMER, "core %u finished\n", lcore_id);
return 0;
}
+static int
+timer_sanity_check(void)
+{
+#ifdef RTE_LIBEAL_USE_HPET
+ if (eal_timer_source != EAL_TIMER_HPET) {
+ printf("Not using HPET, can't sanity check timer sources\n");
+ return 0;
+ }
+
+ const uint64_t t_hz = rte_get_tsc_hz();
+ const uint64_t h_hz = rte_get_hpet_hz();
+ printf("Hertz values: TSC = %"PRIu64", HPET = %"PRIu64"\n", t_hz, h_hz);
+
+ const uint64_t tsc_start = rte_get_tsc_cycles();
+ const uint64_t hpet_start = rte_get_hpet_cycles();
+ rte_delay_ms(100); /* delay 1/10 second */
+ const uint64_t tsc_end = rte_get_tsc_cycles();
+ const uint64_t hpet_end = rte_get_hpet_cycles();
+ printf("Measured cycles: TSC = %"PRIu64", HPET = %"PRIu64"\n",
+ tsc_end-tsc_start, hpet_end-hpet_start);
+
+ const double tsc_time = (double)(tsc_end - tsc_start)/t_hz;
+ const double hpet_time = (double)(hpet_end - hpet_start)/h_hz;
+ /* get the percentage that the times differ by */
+ const double time_diff = fabs(tsc_time - hpet_time)*100/tsc_time;
+ printf("Measured time: TSC = %.4f, HPET = %.4f\n", tsc_time, hpet_time);
+
+ printf("Elapsed time measured by TSC and HPET differ by %f%%\n",
+ time_diff);
+ if (time_diff > 0.1) {
+ printf("Error times differ by >0.1%%");
+ return -1;
+ }
+#endif
+ return 0;
+}
+
int
test_timer(void)
{
uint64_t cur_time;
uint64_t hz;
+ /* sanity check our timer sources and timer config values */
+ if (timer_sanity_check() < 0) {
+ printf("Timer sanity checks failed\n");
+ return -1;
+ }
+
if (rte_lcore_count() < 2) {
printf("not enough lcores for this test\n");
return -1;
}
/* calculate the "end of test" time */
- cur_time = rte_get_hpet_cycles();
- hz = rte_get_hpet_hz();
+ cur_time = rte_get_timer_cycles();
+ hz = rte_get_timer_hz();
end_time = cur_time + (hz * TEST_DURATION_S);
/* start other cores */
rte_timer_stop_sync(&mytiminfo[0].tim);
/* calculate the "end of test" time */
- cur_time = rte_get_hpet_cycles();
- hz = rte_get_hpet_hz();
+ cur_time = rte_get_timer_cycles();
+ hz = rte_get_timer_hz();
end_time = cur_time + (hz * TEST_DURATION_S);
/* start other cores */
CONFIG_RTE_MAX_TAILQ=32
CONFIG_RTE_LOG_LEVEL=8
CONFIG_RTE_LOG_HISTORY=256
-CONFIG_RTE_LIBEAL_USE_HPET=y
+CONFIG_RTE_LIBEAL_USE_HPET=n
CONFIG_RTE_EAL_ALLOW_INV_SOCKET_ID=n
CONFIG_RTE_EAL_ALWAYS_PANIC_ON_ERROR=n
CONFIG_RTE_EAL_UNBIND_PORTS=n
CONFIG_RTE_MAX_TAILQ=32
CONFIG_RTE_LOG_LEVEL=8
CONFIG_RTE_LOG_HISTORY=256
-CONFIG_RTE_LIBEAL_USE_HPET=y
+CONFIG_RTE_LIBEAL_USE_HPET=n
CONFIG_RTE_EAL_ALLOW_INV_SOCKET_ID=n
CONFIG_RTE_EAL_ALWAYS_PANIC_ON_ERROR=n
CONFIG_RTE_EAL_UNBIND_PORTS=n
CONFIG_RTE_MAX_TAILQ=32
CONFIG_RTE_LOG_LEVEL=8
CONFIG_RTE_LOG_HISTORY=256
-CONFIG_RTE_LIBEAL_USE_HPET=y
+CONFIG_RTE_LIBEAL_USE_HPET=n
CONFIG_RTE_EAL_ALLOW_INV_SOCKET_ID=n
CONFIG_RTE_EAL_ALWAYS_PANIC_ON_ERROR=n
CONFIG_RTE_EAL_UNBIND_PORTS=n
CONFIG_RTE_MAX_TAILQ=32
CONFIG_RTE_LOG_LEVEL=8
CONFIG_RTE_LOG_HISTORY=256
-CONFIG_RTE_LIBEAL_USE_HPET=y
+CONFIG_RTE_LIBEAL_USE_HPET=n
CONFIG_RTE_EAL_ALLOW_INV_SOCKET_ID=n
CONFIG_RTE_EAL_ALWAYS_PANIC_ON_ERROR=n
CONFIG_RTE_EAL_UNBIND_PORTS=n
printf("%s() on lcore %u\n", __func__, lcore_id);
/* reload it on another lcore */
- hz = rte_get_hpet_hz();
+ hz = rte_get_timer_hz();
lcore_id = rte_get_next_lcore(lcore_id, 0, 1);
rte_timer_reset(tim, hz/3, SINGLE, lcore_id, timer1_cb, NULL);
}
rte_timer_init(&timer1);
/* load timer0, every second, on master lcore, reloaded automatically */
- hz = rte_get_hpet_hz();
+ hz = rte_get_timer_hz();
lcore_id = rte_lcore_id();
rte_timer_reset(&timer0, hz, PERIODICAL, lcore_id, timer0_cb, NULL);
#ifndef _EAL_PRIVATE_H_
#define _EAL_PRIVATE_H_
+#include <stdio.h>
+
/**
* Initialize the memzone subsystem (private to eal).
*
int rte_eal_memory_init(void);
/**
- * Configure HPET
+ * Configure timers
*
* This function is private to EAL.
*
* Mmap memory areas used by HPET (high precision event timer) that will
- * provide our time reference.
+ * provide our time reference, and configure the TSC frequency also for it
+ * to be used as a reference.
*
* @return
* 0 on success, negative on error
*/
-int rte_eal_hpet_init(void);
+int rte_eal_timer_init(void);
/**
* Init early logs
#endif
#include <stdint.h>
+#include <rte_debug.h>
#ifdef RTE_LIBRTE_EAL_VMWARE_TSC_MAP_SUPPORT
/** Global switch to use VMWARE mapping of TSC instead of RDTSC */
#include <rte_branch_prediction.h>
#endif
+#define MS_PER_S 1000
+#define US_PER_S 1000000
+#define NS_PER_S 1000000000
+
+enum timer_source {
+ EAL_TIMER_TSC = 0,
+ EAL_TIMER_HPET
+};
+extern enum timer_source eal_timer_source;
/**
* Read the TSC register.
return tsc.tsc_64;
}
+/**
+ * Get the measured frequency of the RDTSC counter
+ *
+ * @return
+ * The TSC frequency for this lcore
+ */
+uint64_t
+rte_get_tsc_hz(void);
+
+/**
+ * Return the number of TSC cycles since boot
+ *
+ * @return
+ * the number of cycles
+ */
+static inline uint64_t
+rte_get_tsc_cycles(void) { return rte_rdtsc(); }
+
+#ifdef RTE_LIBEAL_USE_HPET
/**
* Return the number of HPET cycles since boot
*
* This counter is global for all execution units. The number of
- * cycles in one second can be retrived using rte_get_hpet_hz().
+ * cycles in one second can be retrieved using rte_get_hpet_hz().
*
* @return
* the number of cycles
rte_get_hpet_cycles(void);
/**
- * Get the number of cycles in one second.
+ * Get the number of HPET cycles in one second.
*
* @return
* The number of cycles in one second.
uint64_t
rte_get_hpet_hz(void);
+/**
+ * Initialise the HPET for use. This must be called before the rte_get_hpet_hz
+ * and rte_get_hpet_cycles APIs are called. If this function does not succeed,
+ * then the HPET functions are unavailable and should not be called.
+ *
+ * @param make_default
+ * If set, the hpet timer becomes the default timer whose values are
+ * returned by the rte_get_timer_hz/cycles API calls
+ *
+ * @return
+ * 0 on success,
+ * -1 on error, and the make_default parameter is ignored.
+ */
+int rte_eal_hpet_init(int make_default);
+
+#endif
+
+/**
+ * Get the number of cycles since boot from the default timer.
+ *
+ * @return
+ * The number of cycles
+ */
+static inline uint64_t
+rte_get_timer_cycles(void)
+{
+ switch(eal_timer_source) {
+ case EAL_TIMER_TSC:
+ return rte_rdtsc();
+ case EAL_TIMER_HPET:
+#ifdef RTE_LIBEAL_USE_HPET
+ return rte_get_hpet_cycles();
+#endif
+ default: rte_panic("Invalid timer source specified\n");
+ }
+}
+
+/**
+ * Get the number of cycles in one second for the default timer.
+ *
+ * @return
+ * The number of cycles in one second.
+ */
+static inline uint64_t
+rte_get_timer_hz(void)
+{
+ switch(eal_timer_source) {
+ case EAL_TIMER_TSC:
+ return rte_get_tsc_hz();
+ case EAL_TIMER_HPET:
+#ifdef RTE_LIBEAL_USE_HPET
+ return rte_get_hpet_hz();
+#endif
+ default: rte_panic("Invalid timer source specified\n");
+ }
+}
+
/**
* Wait at least us microseconds.
*
SRCS-$(CONFIG_RTE_LIBRTE_EAL_LINUXAPP) += eal_pci.c
SRCS-$(CONFIG_RTE_LIBRTE_EAL_LINUXAPP) += eal_debug.c
SRCS-$(CONFIG_RTE_LIBRTE_EAL_LINUXAPP) += eal_lcore.c
-SRCS-$(CONFIG_RTE_LIBRTE_EAL_LINUXAPP) += eal_hpet.c
+SRCS-$(CONFIG_RTE_LIBRTE_EAL_LINUXAPP) += eal_timer.c
SRCS-$(CONFIG_RTE_LIBRTE_EAL_LINUXAPP) += eal_interrupts.c
SRCS-$(CONFIG_RTE_LIBRTE_EAL_LINUXAPP) += eal_alarm.c
if (rte_eal_intr_init() < 0)
rte_panic("Cannot init interrupt-handling thread\n");
- if (rte_eal_hpet_init() < 0)
- rte_panic("Cannot init HPET\n");
+ if (rte_eal_timer_init() < 0)
+ rte_panic("Cannot init HPET or TSC timers\n");
if (rte_eal_pci_init() < 0)
rte_panic("Cannot init PCI\n");
+++ /dev/null
-/*-
- * BSD LICENSE
- *
- * Copyright(c) 2010-2013 Intel Corporation. All rights reserved.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Intel Corporation nor the names of its
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include <string.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <stdarg.h>
-#include <stdint.h>
-#include <fcntl.h>
-#include <inttypes.h>
-#include <sys/mman.h>
-#include <sys/queue.h>
-#include <unistd.h>
-#include <pthread.h>
-#include <errno.h>
-
-#include <rte_common.h>
-#include <rte_log.h>
-#include <rte_cycles.h>
-#include <rte_tailq.h>
-#include <rte_memory.h>
-#include <rte_memzone.h>
-#include <rte_eal.h>
-
-#include "eal_private.h"
-#include "eal_internal_cfg.h"
-
-#define DEV_HPET "/dev/hpet"
-
-/* Maximum number of counters. */
-#define HPET_TIMER_NUM 3
-
-/* General capabilities register */
-#define CLK_PERIOD_SHIFT 32 /* Clock period shift. */
-#define CLK_PERIOD_MASK 0xffffffff00000000ULL /* Clock period mask. */
-#define COUNT_SIZE_CAP_SHIFT 13 /* Count size capa. shift. */
-#define COUNT_SIZE_CAP_MASK 0x0000000000002000ULL /* Count size capa. mask. */
-
-/**
- * HPET timer registers. From the Intel IA-PC HPET (High Precision Event
- * Timers) Specification.
- */
-struct eal_hpet_regs {
- /* Memory-mapped, software visible registers */
- uint64_t capabilities; /**< RO General Capabilities Register. */
- uint64_t reserved0; /**< Reserved for future use. */
- uint64_t config; /**< RW General Configuration Register. */
- uint64_t reserved1; /**< Reserved for future use. */
- uint64_t isr; /**< RW Clear General Interrupt Status. */
- uint64_t reserved2[25]; /**< Reserved for future use. */
- union {
- uint64_t counter; /**< RW Main Counter Value Register. */
- struct {
- uint32_t counter_l; /**< RW Main Counter Low. */
- uint32_t counter_h; /**< RW Main Counter High. */
- };
- };
- uint64_t reserved3; /**< Reserved for future use. */
- struct {
- uint64_t config; /**< RW Timer Config and Capability Reg. */
- uint64_t comp; /**< RW Timer Comparator Value Register. */
- uint64_t fsb; /**< RW FSB Interrupt Route Register. */
- uint64_t reserved4; /**< Reserved for future use. */
- } timers[HPET_TIMER_NUM]; /**< Set of HPET timers. */
-};
-
-/* Mmap'd hpet registers */
-static volatile struct eal_hpet_regs *eal_hpet = NULL;
-
-/* Period at which the counter increments in femtoseconds (10^-15 seconds). */
-static uint32_t eal_hpet_resolution_fs = 0;
-
-/* Frequency of the counter in Hz */
-static uint64_t eal_hpet_resolution_hz = 0;
-
-/* Incremented 4 times during one 32bits hpet full count */
-static uint32_t eal_hpet_msb;
-
-static pthread_t msb_inc_thread_id;
-
-/*
- * This function runs on a specific thread to update a global variable
- * containing used to process MSB of the HPET (unfortunatelly, we need
- * this because hpet is 32 bits by default under linux).
- */
-static __attribute__((noreturn)) void *
-hpet_msb_inc(__attribute__((unused)) void *arg)
-{
- uint32_t t;
-
- while (1) {
- t = (eal_hpet->counter_l >> 30);
- if (t != (eal_hpet_msb & 3))
- eal_hpet_msb ++;
- sleep(10);
- }
-}
-
-static inline void
-set_rdtsc_freq(void)
-{
- uint64_t start;
-
- start = rte_rdtsc();
- sleep(1);
- eal_hpet_resolution_hz = rte_rdtsc() - start;
- eal_hpet_resolution_fs = (uint32_t)
- ((1.0 / eal_hpet_resolution_hz) / 1e-15);
-}
-
-/*
- * Open and mmap /dev/hpet (high precision event timer) that will
- * provide our time reference.
- */
-int
-rte_eal_hpet_init(void)
-{
- int fd, ret;
-
- if (internal_config.no_hpet) {
- goto use_rdtsc;
- }
-
- fd = open(DEV_HPET, O_RDONLY);
- if (fd < 0) {
- RTE_LOG(WARNING, EAL, "WARNING: Cannot open "DEV_HPET": %s! "
- "The TSC will be used instead.\n",
- strerror(errno));
- goto use_rdtsc;
- }
- eal_hpet = mmap(NULL, 1024, PROT_READ, MAP_SHARED, fd, 0);
- if (eal_hpet == MAP_FAILED) {
- RTE_LOG(WARNING, EAL, "WARNING: Cannot mmap "DEV_HPET"! "
- "The TSC will be used instead.\n");
- close(fd);
- goto use_rdtsc;
- }
- close(fd);
-
- eal_hpet_resolution_fs = (uint32_t)((eal_hpet->capabilities &
- CLK_PERIOD_MASK) >>
- CLK_PERIOD_SHIFT);
-
- eal_hpet_resolution_hz = (1000ULL*1000ULL*1000ULL*1000ULL*1000ULL) /
- (uint64_t)eal_hpet_resolution_fs;
-
- eal_hpet_msb = (eal_hpet->counter_l >> 30);
-
- /* create a thread that will increment a global variable for
- * msb (hpet is 32 bits by default under linux) */
- ret = pthread_create(&msb_inc_thread_id, NULL, hpet_msb_inc, NULL);
- if (ret < 0) {
- RTE_LOG(WARNING, EAL, "WARNING: Cannot create HPET timer thread! "
- "The TSC will be used instead.\n");
- goto use_rdtsc;
- }
-
- return 0;
-
-use_rdtsc:
- internal_config.no_hpet = 1;
- set_rdtsc_freq();
- return 0;
-}
-
-uint64_t
-rte_get_hpet_hz(void)
-{
- return eal_hpet_resolution_hz;
-}
-
-uint64_t
-rte_get_hpet_cycles(void)
-{
- uint32_t t, msb;
- uint64_t ret;
-
- if(internal_config.no_hpet)
- /* fallback to rdtsc */
- return rte_rdtsc();
-
- t = eal_hpet->counter_l;
- msb = eal_hpet_msb;
- ret = (msb + 2 - (t >> 30)) / 4;
- ret <<= 32;
- ret += t;
- return ret;
-}
-
-void
-rte_delay_us(unsigned us)
-{
- uint64_t start;
- uint64_t ticks;
- ticks = (uint64_t)us * 1000ULL * 1000ULL * 1000ULL;
- ticks /= eal_hpet_resolution_fs;
- start = rte_get_hpet_cycles();
- while ((rte_get_hpet_cycles() - start) < ticks)
- rte_pause();
-}
--- /dev/null
+/*-
+ * BSD LICENSE
+ *
+ * Copyright(c) 2010-2013 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <sys/mman.h>
+#include <sys/queue.h>
+#include <pthread.h>
+#include <errno.h>
+
+#include <rte_common.h>
+#include <rte_log.h>
+#include <rte_cycles.h>
+#include <rte_tailq.h>
+#include <rte_memory.h>
+#include <rte_memzone.h>
+#include <rte_eal.h>
+#include <rte_debug.h>
+
+#include "eal_private.h"
+#include "eal_internal_cfg.h"
+
+enum timer_source eal_timer_source = EAL_TIMER_HPET;
+
+/* The frequency of the RDTSC timer resolution */
+static uint64_t eal_tsc_resolution_hz = 0;
+
+#ifdef RTE_LIBEAL_USE_HPET
+
+#define DEV_HPET "/dev/hpet"
+
+/* Maximum number of counters. */
+#define HPET_TIMER_NUM 3
+
+/* General capabilities register */
+#define CLK_PERIOD_SHIFT 32 /* Clock period shift. */
+#define CLK_PERIOD_MASK 0xffffffff00000000ULL /* Clock period mask. */
+#define COUNT_SIZE_CAP_SHIFT 13 /* Count size capa. shift. */
+#define COUNT_SIZE_CAP_MASK 0x0000000000002000ULL /* Count size capa. mask. */
+
+/**
+ * HPET timer registers. From the Intel IA-PC HPET (High Precision Event
+ * Timers) Specification.
+ */
+struct eal_hpet_regs {
+ /* Memory-mapped, software visible registers */
+ uint64_t capabilities; /**< RO General Capabilities Register. */
+ uint64_t reserved0; /**< Reserved for future use. */
+ uint64_t config; /**< RW General Configuration Register. */
+ uint64_t reserved1; /**< Reserved for future use. */
+ uint64_t isr; /**< RW Clear General Interrupt Status. */
+ uint64_t reserved2[25]; /**< Reserved for future use. */
+ union {
+ uint64_t counter; /**< RW Main Counter Value Register. */
+ struct {
+ uint32_t counter_l; /**< RW Main Counter Low. */
+ uint32_t counter_h; /**< RW Main Counter High. */
+ };
+ };
+ uint64_t reserved3; /**< Reserved for future use. */
+ struct {
+ uint64_t config; /**< RW Timer Config and Capability Reg. */
+ uint64_t comp; /**< RW Timer Comparator Value Register. */
+ uint64_t fsb; /**< RW FSB Interrupt Route Register. */
+ uint64_t reserved4; /**< Reserved for future use. */
+ } timers[HPET_TIMER_NUM]; /**< Set of HPET timers. */
+};
+
+/* Mmap'd hpet registers */
+static volatile struct eal_hpet_regs *eal_hpet = NULL;
+
+/* Period at which the HPET counter increments in
+ * femtoseconds (10^-15 seconds). */
+static uint32_t eal_hpet_resolution_fs = 0;
+
+/* Frequency of the HPET counter in Hz */
+static uint64_t eal_hpet_resolution_hz = 0;
+
+/* Incremented 4 times during one 32bits hpet full count */
+static uint32_t eal_hpet_msb;
+
+static pthread_t msb_inc_thread_id;
+
+/*
+ * This function runs on a specific thread to update a global variable
+ * containing used to process MSB of the HPET (unfortunatelly, we need
+ * this because hpet is 32 bits by default under linux).
+ */
+static void
+hpet_msb_inc(__attribute__((unused)) void *arg)
+{
+ uint32_t t;
+
+ while (1) {
+ t = (eal_hpet->counter_l >> 30);
+ if (t != (eal_hpet_msb & 3))
+ eal_hpet_msb ++;
+ sleep(10);
+ }
+}
+
+uint64_t
+rte_get_hpet_hz(void)
+{
+ if(internal_config.no_hpet)
+ rte_panic("Error, HPET called, but no HPET present\n");
+
+ return eal_hpet_resolution_hz;
+}
+
+uint64_t
+rte_get_hpet_cycles(void)
+{
+ uint32_t t, msb;
+ uint64_t ret;
+
+ if(internal_config.no_hpet)
+ rte_panic("Error, HPET called, but no HPET present\n");
+
+ t = eal_hpet->counter_l;
+ msb = eal_hpet_msb;
+ ret = (msb + 2 - (t >> 30)) / 4;
+ ret <<= 32;
+ ret += t;
+ return ret;
+}
+
+#endif
+
+
+void
+rte_delay_us(unsigned us)
+{
+ const uint64_t start = rte_get_timer_cycles();
+ const uint64_t ticks = (uint64_t)us * rte_get_timer_hz() / 1E6;
+ while ((rte_get_timer_cycles() - start) < ticks)
+ rte_pause();
+}
+
+uint64_t
+rte_get_tsc_hz(void)
+{
+ return eal_tsc_resolution_hz;
+}
+
+
+#ifdef RTE_LIBEAL_USE_HPET
+/*
+ * Open and mmap /dev/hpet (high precision event timer) that will
+ * provide our time reference.
+ */
+int
+rte_eal_hpet_init(int make_default)
+{
+ int fd, ret;
+
+ if (internal_config.no_hpet) {
+ RTE_LOG(INFO, EAL, "HPET is disabled\n");
+ return -1;
+ }
+
+ fd = open(DEV_HPET, O_RDONLY);
+ if (fd < 0) {
+ RTE_LOG(ERR, EAL, "ERROR: Cannot open "DEV_HPET": %s!\n",
+ strerror(errno));
+ internal_config.no_hpet = 1;
+ return -1;
+ }
+ eal_hpet = mmap(NULL, 1024, PROT_READ, MAP_SHARED, fd, 0);
+ if (eal_hpet == MAP_FAILED) {
+ RTE_LOG(ERR, EAL, "ERROR: Cannot mmap "DEV_HPET"!\n"
+ "Please enable CONFIG_HPET_MMAP in your kernel configuration "
+ "to allow HPET support.\n"
+ "To run without using HPET, set CONFIG_RTE_LIBEAL_USE_HPET=n "
+ "in your build configuration or use '--no-hpet' EAL flag.\n");
+ close(fd);
+ internal_config.no_hpet = 1;
+ return -1;
+ }
+ close(fd);
+
+ eal_hpet_resolution_fs = (uint32_t)((eal_hpet->capabilities &
+ CLK_PERIOD_MASK) >>
+ CLK_PERIOD_SHIFT);
+
+ eal_hpet_resolution_hz = (1000ULL*1000ULL*1000ULL*1000ULL*1000ULL) /
+ (uint64_t)eal_hpet_resolution_fs;
+
+ RTE_LOG(INFO, EAL, "HPET frequency is ~%"PRIu64" kHz\n",
+ eal_hpet_resolution_hz/1000);
+
+ eal_hpet_msb = (eal_hpet->counter_l >> 30);
+
+ /* create a thread that will increment a global variable for
+ * msb (hpet is 32 bits by default under linux) */
+ ret = pthread_create(&msb_inc_thread_id, NULL,
+ (void *(*)(void *))hpet_msb_inc, NULL);
+ if (ret < 0) {
+ RTE_LOG(ERR, EAL, "ERROR: Cannot create HPET timer thread!\n");
+ internal_config.no_hpet = 1;
+ return -1;
+ }
+
+ if (make_default)
+ eal_timer_source = EAL_TIMER_HPET;
+ return 0;
+}
+#endif
+
+static int
+set_tsc_freq_from_clock(void)
+{
+#ifdef CLOCK_MONOTONIC_RAW
+#define NS_PER_SEC 1E9
+
+ struct timespec sleeptime = {.tv_nsec = 5E8 }; /* 1/2 second */
+
+ struct timespec t_start, t_end;
+
+ if (clock_gettime(CLOCK_MONOTONIC_RAW, &t_start) == 0) {
+ uint64_t ns, end, start = rte_rdtsc();
+ nanosleep(&sleeptime,NULL);
+ clock_gettime(CLOCK_MONOTONIC_RAW, &t_end);
+ end = rte_rdtsc();
+ ns = ((t_end.tv_sec - t_start.tv_sec) * NS_PER_SEC);
+ ns += (t_end.tv_nsec - t_start.tv_nsec);
+
+ double secs = (double)ns/NS_PER_SEC;
+ eal_tsc_resolution_hz = (uint64_t)((end - start)/secs);
+ return 0;
+ }
+#endif
+ return -1;
+}
+
+static void
+set_tsc_freq_fallback(void)
+{
+ RTE_LOG(WARNING, EAL, "WARNING: clock_gettime cannot use "
+ "CLOCK_MONOTONIC_RAW and HPET is not available"
+ " - clock timings may be less accurate.\n");
+ /* assume that the sleep(1) will sleep for 1 second */
+ uint64_t start = rte_rdtsc();
+ sleep(1);
+ eal_tsc_resolution_hz = rte_rdtsc() - start;
+}
+/*
+ * This function measures the TSC frequency. It uses a variety of approaches.
+ *
+ * 1. If kernel provides CLOCK_MONOTONIC_RAW we use that to tune the TSC value
+ * 2. If kernel does not provide that, and we have HPET support, tune using HPET
+ * 3. Lastly, if neither of the above can be used, just sleep for 1 second and
+ * tune off that, printing a warning about inaccuracy of timing
+ */
+static void
+set_tsc_freq(void)
+{
+ if (set_tsc_freq_from_clock() < 0)
+ set_tsc_freq_fallback();
+
+ RTE_LOG(INFO, EAL, "TSC frequency is ~%"PRIu64" KHz\n",
+ eal_tsc_resolution_hz/1000);
+}
+
+int
+rte_eal_timer_init(void)
+{
+
+ eal_timer_source = EAL_TIMER_TSC;
+
+ set_tsc_freq();
+ return 0;
+}
static void
timer_add(struct rte_timer *tim, unsigned tim_lcore, int local_is_locked)
{
- uint64_t cur_time = rte_get_hpet_cycles();
+ uint64_t cur_time = rte_get_timer_cycles();
unsigned lcore_id = rte_lcore_id();
struct rte_timer *t, *t_prev;
enum rte_timer_type type, unsigned tim_lcore,
rte_timer_cb_t fct, void *arg)
{
- uint64_t cur_time = rte_get_hpet_cycles();
+ uint64_t cur_time = rte_get_timer_cycles();
uint64_t period;
if (unlikely((tim_lcore != (unsigned)LCORE_ID_ANY) &&
uint64_t cur_time;
int ret;
+ __TIMER_STAT_ADD(manage, 1);
/* optimize for the case where per-cpu list is empty */
if (LIST_EMPTY(&priv_timer[lcore_id].pending))
return;
-
- cur_time = rte_get_hpet_cycles();
- __TIMER_STAT_ADD(manage, 1);
+ cur_time = rte_get_timer_cycles();
/* browse ordered list, add expired timers in 'expired' list */
rte_spinlock_lock(&priv_timer[lcore_id].list_lock);
#
EXECENV_CFLAGS = -pthread
-EXECENV_LDFLAGS =
+EXECENV_LDFLAGS =
+EXECENV_LDLIBS = -lrt
EXECENV_ASFLAGS =
# force applications to link with gcc/icc instead of using ld
ifeq ($(CONFIG_RTE_LIBC),y)
LDLIBS += -lc
+LDLIBS += -lm
endif
ifeq ($(CONFIG_RTE_LIBGLOSS),y)