/*-
* BSD LICENSE
- *
+ *
* Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
* Copyright(c) 2012-2013 6WIND S.A.
* 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
* * 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
#include <rte_common.h>
#include <rte_log.h>
#include <rte_cycles.h>
-#include <rte_tailq.h>
+#include <rte_lcore.h>
#include <rte_memory.h>
-#include <rte_memzone.h>
#include <rte_eal.h>
#include <rte_debug.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"
/* 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
/*
* This function runs on a specific thread to update a global variable
- * containing used to process MSB of the HPET (unfortunatelly, we need
+ * containing used to process MSB of the HPET (unfortunately, we need
* this because hpet is 32 bits by default under linux).
*/
static void
#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
rte_eal_hpet_init(int make_default)
{
int fd, ret;
+ char thread_name[RTE_MAX_THREAD_NAME_LEN];
if (internal_config.no_hpet) {
- RTE_LOG(INFO, EAL, "HPET is disabled\n");
+ RTE_LOG(NOTICE, EAL, "HPET is disabled\n");
return -1;
}
/* 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,
+ ret = rte_ctrl_thread_create(&msb_inc_thread_id, NULL,
(void *(*)(void *))hpet_msb_inc, NULL);
- if (ret < 0) {
+ if (ret != 0) {
RTE_LOG(ERR, EAL, "ERROR: Cannot create HPET timer thread!\n");
internal_config.no_hpet = 1;
return -1;
}
+ /*
+ * Set thread_name for aid in debugging.
+ */
+ snprintf(thread_name, RTE_MAX_THREAD_NAME_LEN, "hpet-msb-inc");
+ ret = rte_thread_setname(msb_inc_thread_id, thread_name);
+ if (ret != 0)
+ RTE_LOG(DEBUG, EAL,
+ "Cannot set HPET timer thread name!\n");
+
if (make_default)
eal_timer_source = EAL_TIMER_HPET;
return 0;
fclose(stream);
}
-static int
-set_tsc_freq_from_cpuinfo(void)
-{
- char line[256];
- FILE *stream;
- double dmhz;
-
- stream = fopen("/proc/cpuinfo", "r");
- if (!stream) {
- RTE_LOG(WARNING, EAL, "WARNING: Unable to open /proc/cpuinfo\n");
- return -1;
- }
-
- while (fgets(line, sizeof line, stream)) {
- if (sscanf(line, "cpu MHz\t: %lf", &dmhz) == 1) {
- eal_tsc_resolution_hz = (uint64_t)(dmhz * 1000000UL);
- break;
- }
- }
-
- fclose(stream);
-
- if (!eal_tsc_resolution_hz) {
- RTE_LOG(WARNING, EAL, "WARNING: Cannot read CPU clock from cpuinfo\n");
- return -1;
- }
- return 0;
-}
-
-static int
-set_tsc_freq_from_clock(void)
+uint64_t
+get_tsc_freq(void)
{
#ifdef CLOCK_MONOTONIC_RAW
#define NS_PER_SEC 1E9
- struct timespec sleeptime = {.tv_nsec = 5E8 }; /* 1/2 second */
+ struct timespec sleeptime = {.tv_nsec = NS_PER_SEC / 10 }; /* 1/10 second */
struct timespec t_start, t_end;
+ uint64_t tsc_hz;
if (clock_gettime(CLOCK_MONOTONIC_RAW, &t_start) == 0) {
uint64_t ns, end, start = rte_rdtsc();
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;
+ tsc_hz = (uint64_t)((end - start)/secs);
+ return tsc_hz;
}
#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_cpuinfo() < 0 &&
- 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);
+ return 0;
}
int