timer.cc revision 9881
19651SAndreas.Sandberg@ARM.com/*
29651SAndreas.Sandberg@ARM.com * Copyright (c) 2012 ARM Limited
39651SAndreas.Sandberg@ARM.com * All rights reserved
49651SAndreas.Sandberg@ARM.com *
59651SAndreas.Sandberg@ARM.com * The license below extends only to copyright in the software and shall
69651SAndreas.Sandberg@ARM.com * not be construed as granting a license to any other intellectual
79651SAndreas.Sandberg@ARM.com * property including but not limited to intellectual property relating
89651SAndreas.Sandberg@ARM.com * to a hardware implementation of the functionality of the software
99651SAndreas.Sandberg@ARM.com * licensed hereunder.  You may use the software subject to the license
109651SAndreas.Sandberg@ARM.com * terms below provided that you ensure that this notice is replicated
119651SAndreas.Sandberg@ARM.com * unmodified and in its entirety in all distributions of the software,
129651SAndreas.Sandberg@ARM.com * modified or unmodified, in source code or in binary form.
139651SAndreas.Sandberg@ARM.com *
149651SAndreas.Sandberg@ARM.com * Redistribution and use in source and binary forms, with or without
159651SAndreas.Sandberg@ARM.com * modification, are permitted provided that the following conditions are
169651SAndreas.Sandberg@ARM.com * met: redistributions of source code must retain the above copyright
179651SAndreas.Sandberg@ARM.com * notice, this list of conditions and the following disclaimer;
189651SAndreas.Sandberg@ARM.com * redistributions in binary form must reproduce the above copyright
199651SAndreas.Sandberg@ARM.com * notice, this list of conditions and the following disclaimer in the
209651SAndreas.Sandberg@ARM.com * documentation and/or other materials provided with the distribution;
219651SAndreas.Sandberg@ARM.com * neither the name of the copyright holders nor the names of its
229651SAndreas.Sandberg@ARM.com * contributors may be used to endorse or promote products derived from
239651SAndreas.Sandberg@ARM.com * this software without specific prior written permission.
249651SAndreas.Sandberg@ARM.com *
259651SAndreas.Sandberg@ARM.com * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
269651SAndreas.Sandberg@ARM.com * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
279651SAndreas.Sandberg@ARM.com * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
289651SAndreas.Sandberg@ARM.com * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
299651SAndreas.Sandberg@ARM.com * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
309651SAndreas.Sandberg@ARM.com * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
319651SAndreas.Sandberg@ARM.com * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
329651SAndreas.Sandberg@ARM.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
339651SAndreas.Sandberg@ARM.com * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
349651SAndreas.Sandberg@ARM.com * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
359651SAndreas.Sandberg@ARM.com * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
369651SAndreas.Sandberg@ARM.com *
379651SAndreas.Sandberg@ARM.com * Authors: Andreas Sandberg
389651SAndreas.Sandberg@ARM.com */
399651SAndreas.Sandberg@ARM.com
409881Sandreas@sandberg.pp.se#include <algorithm>
419651SAndreas.Sandberg@ARM.com#include <csignal>
429651SAndreas.Sandberg@ARM.com#include <ctime>
439651SAndreas.Sandberg@ARM.com
449651SAndreas.Sandberg@ARM.com#include "base/misc.hh"
459651SAndreas.Sandberg@ARM.com#include "base/trace.hh"
469651SAndreas.Sandberg@ARM.com#include "cpu/kvm/timer.hh"
479651SAndreas.Sandberg@ARM.com#include "debug/KvmTimer.hh"
489651SAndreas.Sandberg@ARM.com
499881Sandreas@sandberg.pp.se/**
509881Sandreas@sandberg.pp.se * Minimum number of cycles that a host can spend in a KVM call (used
519881Sandreas@sandberg.pp.se * to calculate the resolution of some timers).
529881Sandreas@sandberg.pp.se *
539881Sandreas@sandberg.pp.se * The value of this constant is a bit arbitrary, but in practice, we
549881Sandreas@sandberg.pp.se * can't really do anything useful in less than ~1000 cycles.
559881Sandreas@sandberg.pp.se */
569881Sandreas@sandberg.pp.sestatic const uint64_t MIN_HOST_CYCLES = 1000;
579651SAndreas.Sandberg@ARM.com
589651SAndreas.Sandberg@ARM.comPosixKvmTimer::PosixKvmTimer(int signo, clockid_t clockID,
599651SAndreas.Sandberg@ARM.com                             float hostFactor, Tick hostFreq)
609651SAndreas.Sandberg@ARM.com    : BaseKvmTimer(signo, hostFactor, hostFreq),
619651SAndreas.Sandberg@ARM.com      clockID(clockID)
629651SAndreas.Sandberg@ARM.com{
639651SAndreas.Sandberg@ARM.com    struct sigevent sev;
649651SAndreas.Sandberg@ARM.com
659651SAndreas.Sandberg@ARM.com    // TODO: We should request signal delivery to thread instead of
669651SAndreas.Sandberg@ARM.com    // the process here. Unfortunately this seems to be broken, or at
679651SAndreas.Sandberg@ARM.com    // least not work as specified in the man page.
689651SAndreas.Sandberg@ARM.com    sev.sigev_notify = SIGEV_SIGNAL;
699651SAndreas.Sandberg@ARM.com    sev.sigev_signo = signo;
709651SAndreas.Sandberg@ARM.com    sev.sigev_value.sival_ptr = NULL;
719734Sandreas@sandberg.pp.se
729734Sandreas@sandberg.pp.se    while (timer_create(clockID, &sev, &timer) == -1) {
739734Sandreas@sandberg.pp.se        if (errno != EAGAIN)
749734Sandreas@sandberg.pp.se            panic("timer_create: %i", errno);
759734Sandreas@sandberg.pp.se    }
769651SAndreas.Sandberg@ARM.com}
779651SAndreas.Sandberg@ARM.com
789651SAndreas.Sandberg@ARM.comPosixKvmTimer::~PosixKvmTimer()
799651SAndreas.Sandberg@ARM.com{
809651SAndreas.Sandberg@ARM.com    timer_delete(timer);
819651SAndreas.Sandberg@ARM.com}
829651SAndreas.Sandberg@ARM.com
839651SAndreas.Sandberg@ARM.comvoid
849651SAndreas.Sandberg@ARM.comPosixKvmTimer::arm(Tick ticks)
859651SAndreas.Sandberg@ARM.com{
869651SAndreas.Sandberg@ARM.com    struct itimerspec ts;
879651SAndreas.Sandberg@ARM.com    memset(&ts, 0, sizeof(ts));
889651SAndreas.Sandberg@ARM.com
899651SAndreas.Sandberg@ARM.com    ts.it_interval.tv_sec = 0;
909651SAndreas.Sandberg@ARM.com    ts.it_interval.tv_nsec = 0;
919651SAndreas.Sandberg@ARM.com    ts.it_value.tv_sec = hostNs(ticks) / 1000000000ULL;
929651SAndreas.Sandberg@ARM.com    ts.it_value.tv_nsec = hostNs(ticks) % 1000000000ULL;
939651SAndreas.Sandberg@ARM.com
949881Sandreas@sandberg.pp.se    assert(ts.it_value.tv_nsec > 0 || ts.it_value.tv_sec > 0);
959881Sandreas@sandberg.pp.se
969651SAndreas.Sandberg@ARM.com    DPRINTF(KvmTimer, "Arming POSIX timer: %i ticks (%is%ins)\n",
979651SAndreas.Sandberg@ARM.com            ticks, ts.it_value.tv_sec, ts.it_value.tv_nsec);
989651SAndreas.Sandberg@ARM.com
999651SAndreas.Sandberg@ARM.com    if (timer_settime(timer, 0, &ts, NULL) == -1)
1009651SAndreas.Sandberg@ARM.com        panic("PosixKvmTimer: Failed to arm timer\n");
1019651SAndreas.Sandberg@ARM.com}
1029651SAndreas.Sandberg@ARM.com
1039651SAndreas.Sandberg@ARM.comvoid
1049651SAndreas.Sandberg@ARM.comPosixKvmTimer::disarm()
1059651SAndreas.Sandberg@ARM.com{
1069651SAndreas.Sandberg@ARM.com    struct itimerspec ts;
1079651SAndreas.Sandberg@ARM.com    memset(&ts, 0, sizeof(ts));
1089651SAndreas.Sandberg@ARM.com
1099651SAndreas.Sandberg@ARM.com    DPRINTF(KvmTimer, "Disarming POSIX timer\n");
1109651SAndreas.Sandberg@ARM.com
1119651SAndreas.Sandberg@ARM.com    if (timer_settime(timer, 0, &ts, NULL) == -1)
1129651SAndreas.Sandberg@ARM.com        panic("PosixKvmTimer: Failed to disarm timer\n");
1139651SAndreas.Sandberg@ARM.com}
1149651SAndreas.Sandberg@ARM.com
1159651SAndreas.Sandberg@ARM.comTick
1169651SAndreas.Sandberg@ARM.comPosixKvmTimer::calcResolution()
1179651SAndreas.Sandberg@ARM.com{
1189651SAndreas.Sandberg@ARM.com    struct timespec ts;
1199651SAndreas.Sandberg@ARM.com
1209651SAndreas.Sandberg@ARM.com    if (clock_getres(clockID, &ts) == -1)
1219651SAndreas.Sandberg@ARM.com        panic("PosixKvmTimer: Failed to get timer resolution\n");
1229651SAndreas.Sandberg@ARM.com
1239881Sandreas@sandberg.pp.se    const uint64_t res_ns(ts.tv_sec * 1000000000ULL + ts.tv_nsec);
1249881Sandreas@sandberg.pp.se    // We preferrably want ticksFromHostNs() to calculate the the
1259881Sandreas@sandberg.pp.se    // ceiling rather than truncating the value. However, there are
1269881Sandreas@sandberg.pp.se    // other cases where truncating is fine, so we just add 1 here to
1279881Sandreas@sandberg.pp.se    // make sure that the actual resolution is strictly less than what
1289881Sandreas@sandberg.pp.se    // we return. We could get all kinds of nasty behavior if
1299881Sandreas@sandberg.pp.se    // arm(resolution) is called and the resulting time is 0 (which
1309881Sandreas@sandberg.pp.se    // could happen if we truncate the results and the resolution is
1319881Sandreas@sandberg.pp.se    // 1ns).
1329881Sandreas@sandberg.pp.se    const Tick resolution(ticksFromHostNs(res_ns) + 1);
1339881Sandreas@sandberg.pp.se    // It might not make sense to enter into KVM for less than a
1349881Sandreas@sandberg.pp.se    // certain number of host cycles. In some systems (e.g., Linux)
1359881Sandreas@sandberg.pp.se    // the resolution of the timer we use is 1ns (a few cycles on most
1369881Sandreas@sandberg.pp.se    // CPUs), which isn't very useful.
1379881Sandreas@sandberg.pp.se    const Tick min_cycles(ticksFromHostCycles(MIN_HOST_CYCLES));
1389651SAndreas.Sandberg@ARM.com
1399881Sandreas@sandberg.pp.se    return std::max(resolution, min_cycles);
1409651SAndreas.Sandberg@ARM.com}
1419655SAndreas.Sandberg@ARM.com
1429655SAndreas.Sandberg@ARM.com
1439655SAndreas.Sandberg@ARM.comPerfKvmTimer::PerfKvmTimer(PerfKvmCounter &ctr,
1449655SAndreas.Sandberg@ARM.com                           int signo, float hostFactor, Tick hostFreq)
1459655SAndreas.Sandberg@ARM.com    : BaseKvmTimer(signo, hostFactor, hostFreq),
1469655SAndreas.Sandberg@ARM.com      hwOverflow(ctr)
1479655SAndreas.Sandberg@ARM.com{
1489655SAndreas.Sandberg@ARM.com    hwOverflow.enableSignals(signo);
1499655SAndreas.Sandberg@ARM.com}
1509655SAndreas.Sandberg@ARM.com
1519655SAndreas.Sandberg@ARM.comPerfKvmTimer::~PerfKvmTimer()
1529655SAndreas.Sandberg@ARM.com{
1539655SAndreas.Sandberg@ARM.com}
1549655SAndreas.Sandberg@ARM.com
1559655SAndreas.Sandberg@ARM.comvoid
1569655SAndreas.Sandberg@ARM.comPerfKvmTimer::arm(Tick ticks)
1579655SAndreas.Sandberg@ARM.com{
1589655SAndreas.Sandberg@ARM.com    hwOverflow.period(hostCycles(ticks));
1599655SAndreas.Sandberg@ARM.com    hwOverflow.refresh(1);
1609655SAndreas.Sandberg@ARM.com}
1619655SAndreas.Sandberg@ARM.com
1629655SAndreas.Sandberg@ARM.comvoid
1639655SAndreas.Sandberg@ARM.comPerfKvmTimer::disarm()
1649655SAndreas.Sandberg@ARM.com{
1659655SAndreas.Sandberg@ARM.com    hwOverflow.stop();
1669655SAndreas.Sandberg@ARM.com}
1679655SAndreas.Sandberg@ARM.com
1689655SAndreas.Sandberg@ARM.comTick
1699655SAndreas.Sandberg@ARM.comPerfKvmTimer::calcResolution()
1709655SAndreas.Sandberg@ARM.com{
1719881Sandreas@sandberg.pp.se    return ticksFromHostCycles(MIN_HOST_CYCLES);
1729655SAndreas.Sandberg@ARM.com}
173