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