timer.cc revision 10073
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> 4310073Sandreas@sandberg.pp.se#include <unistd.h> 4410073Sandreas@sandberg.pp.se#include <sys/syscall.h> 459651SAndreas.Sandberg@ARM.com 469651SAndreas.Sandberg@ARM.com#include "base/misc.hh" 479651SAndreas.Sandberg@ARM.com#include "base/trace.hh" 489651SAndreas.Sandberg@ARM.com#include "cpu/kvm/timer.hh" 499651SAndreas.Sandberg@ARM.com#include "debug/KvmTimer.hh" 509651SAndreas.Sandberg@ARM.com 5110073Sandreas@sandberg.pp.se/* According to timer_create(2), the value SIGEV_THREAD_ID can be used 5210073Sandreas@sandberg.pp.se * to specify which thread a timer signal gets delivered to. According 5310073Sandreas@sandberg.pp.se * to the man page, the member sigev_notify_thread is used to specify 5410073Sandreas@sandberg.pp.se * the TID. This member is currently not defined by default in 5510073Sandreas@sandberg.pp.se * siginfo.h on x86, so we define it here as a workaround. 5610073Sandreas@sandberg.pp.se */ 5710073Sandreas@sandberg.pp.se#ifndef sigev_notify_thread_id 5810073Sandreas@sandberg.pp.se#define sigev_notify_thread_id _sigev_un._tid 5910073Sandreas@sandberg.pp.se#endif 6010073Sandreas@sandberg.pp.se 6110073Sandreas@sandberg.pp.sestatic pid_t 6210073Sandreas@sandberg.pp.segettid() 6310073Sandreas@sandberg.pp.se{ 6410073Sandreas@sandberg.pp.se return syscall(__NR_gettid); 6510073Sandreas@sandberg.pp.se} 6610073Sandreas@sandberg.pp.se 679881Sandreas@sandberg.pp.se/** 689881Sandreas@sandberg.pp.se * Minimum number of cycles that a host can spend in a KVM call (used 699881Sandreas@sandberg.pp.se * to calculate the resolution of some timers). 709881Sandreas@sandberg.pp.se * 719881Sandreas@sandberg.pp.se * The value of this constant is a bit arbitrary, but in practice, we 729881Sandreas@sandberg.pp.se * can't really do anything useful in less than ~1000 cycles. 739881Sandreas@sandberg.pp.se */ 749881Sandreas@sandberg.pp.sestatic const uint64_t MIN_HOST_CYCLES = 1000; 759651SAndreas.Sandberg@ARM.com 769651SAndreas.Sandberg@ARM.comPosixKvmTimer::PosixKvmTimer(int signo, clockid_t clockID, 779651SAndreas.Sandberg@ARM.com float hostFactor, Tick hostFreq) 789651SAndreas.Sandberg@ARM.com : BaseKvmTimer(signo, hostFactor, hostFreq), 799651SAndreas.Sandberg@ARM.com clockID(clockID) 809651SAndreas.Sandberg@ARM.com{ 819651SAndreas.Sandberg@ARM.com struct sigevent sev; 829651SAndreas.Sandberg@ARM.com 8310073Sandreas@sandberg.pp.se sev.sigev_notify = SIGEV_THREAD_ID; 849651SAndreas.Sandberg@ARM.com sev.sigev_signo = signo; 8510073Sandreas@sandberg.pp.se sev.sigev_notify_thread_id = gettid(); 869651SAndreas.Sandberg@ARM.com sev.sigev_value.sival_ptr = NULL; 879734Sandreas@sandberg.pp.se 889734Sandreas@sandberg.pp.se while (timer_create(clockID, &sev, &timer) == -1) { 899734Sandreas@sandberg.pp.se if (errno != EAGAIN) 909734Sandreas@sandberg.pp.se panic("timer_create: %i", errno); 919734Sandreas@sandberg.pp.se } 929651SAndreas.Sandberg@ARM.com} 939651SAndreas.Sandberg@ARM.com 949651SAndreas.Sandberg@ARM.comPosixKvmTimer::~PosixKvmTimer() 959651SAndreas.Sandberg@ARM.com{ 969651SAndreas.Sandberg@ARM.com timer_delete(timer); 979651SAndreas.Sandberg@ARM.com} 989651SAndreas.Sandberg@ARM.com 999651SAndreas.Sandberg@ARM.comvoid 1009651SAndreas.Sandberg@ARM.comPosixKvmTimer::arm(Tick ticks) 1019651SAndreas.Sandberg@ARM.com{ 1029651SAndreas.Sandberg@ARM.com struct itimerspec ts; 1039651SAndreas.Sandberg@ARM.com memset(&ts, 0, sizeof(ts)); 1049651SAndreas.Sandberg@ARM.com 1059651SAndreas.Sandberg@ARM.com ts.it_interval.tv_sec = 0; 1069651SAndreas.Sandberg@ARM.com ts.it_interval.tv_nsec = 0; 1079651SAndreas.Sandberg@ARM.com ts.it_value.tv_sec = hostNs(ticks) / 1000000000ULL; 1089651SAndreas.Sandberg@ARM.com ts.it_value.tv_nsec = hostNs(ticks) % 1000000000ULL; 1099651SAndreas.Sandberg@ARM.com 1109881Sandreas@sandberg.pp.se assert(ts.it_value.tv_nsec > 0 || ts.it_value.tv_sec > 0); 1119881Sandreas@sandberg.pp.se 1129651SAndreas.Sandberg@ARM.com DPRINTF(KvmTimer, "Arming POSIX timer: %i ticks (%is%ins)\n", 1139651SAndreas.Sandberg@ARM.com ticks, ts.it_value.tv_sec, ts.it_value.tv_nsec); 1149651SAndreas.Sandberg@ARM.com 1159651SAndreas.Sandberg@ARM.com if (timer_settime(timer, 0, &ts, NULL) == -1) 1169651SAndreas.Sandberg@ARM.com panic("PosixKvmTimer: Failed to arm timer\n"); 1179651SAndreas.Sandberg@ARM.com} 1189651SAndreas.Sandberg@ARM.com 1199651SAndreas.Sandberg@ARM.comvoid 1209651SAndreas.Sandberg@ARM.comPosixKvmTimer::disarm() 1219651SAndreas.Sandberg@ARM.com{ 1229651SAndreas.Sandberg@ARM.com struct itimerspec ts; 1239651SAndreas.Sandberg@ARM.com memset(&ts, 0, sizeof(ts)); 1249651SAndreas.Sandberg@ARM.com 1259651SAndreas.Sandberg@ARM.com DPRINTF(KvmTimer, "Disarming POSIX timer\n"); 1269651SAndreas.Sandberg@ARM.com 1279651SAndreas.Sandberg@ARM.com if (timer_settime(timer, 0, &ts, NULL) == -1) 1289651SAndreas.Sandberg@ARM.com panic("PosixKvmTimer: Failed to disarm timer\n"); 1299651SAndreas.Sandberg@ARM.com} 1309651SAndreas.Sandberg@ARM.com 1319651SAndreas.Sandberg@ARM.comTick 1329651SAndreas.Sandberg@ARM.comPosixKvmTimer::calcResolution() 1339651SAndreas.Sandberg@ARM.com{ 1349651SAndreas.Sandberg@ARM.com struct timespec ts; 1359651SAndreas.Sandberg@ARM.com 1369651SAndreas.Sandberg@ARM.com if (clock_getres(clockID, &ts) == -1) 1379651SAndreas.Sandberg@ARM.com panic("PosixKvmTimer: Failed to get timer resolution\n"); 1389651SAndreas.Sandberg@ARM.com 1399881Sandreas@sandberg.pp.se const uint64_t res_ns(ts.tv_sec * 1000000000ULL + ts.tv_nsec); 1409881Sandreas@sandberg.pp.se // We preferrably want ticksFromHostNs() to calculate the the 1419881Sandreas@sandberg.pp.se // ceiling rather than truncating the value. However, there are 1429881Sandreas@sandberg.pp.se // other cases where truncating is fine, so we just add 1 here to 1439881Sandreas@sandberg.pp.se // make sure that the actual resolution is strictly less than what 1449881Sandreas@sandberg.pp.se // we return. We could get all kinds of nasty behavior if 1459881Sandreas@sandberg.pp.se // arm(resolution) is called and the resulting time is 0 (which 1469881Sandreas@sandberg.pp.se // could happen if we truncate the results and the resolution is 1479881Sandreas@sandberg.pp.se // 1ns). 1489881Sandreas@sandberg.pp.se const Tick resolution(ticksFromHostNs(res_ns) + 1); 1499881Sandreas@sandberg.pp.se // It might not make sense to enter into KVM for less than a 1509881Sandreas@sandberg.pp.se // certain number of host cycles. In some systems (e.g., Linux) 1519881Sandreas@sandberg.pp.se // the resolution of the timer we use is 1ns (a few cycles on most 1529881Sandreas@sandberg.pp.se // CPUs), which isn't very useful. 1539881Sandreas@sandberg.pp.se const Tick min_cycles(ticksFromHostCycles(MIN_HOST_CYCLES)); 1549651SAndreas.Sandberg@ARM.com 1559881Sandreas@sandberg.pp.se return std::max(resolution, min_cycles); 1569651SAndreas.Sandberg@ARM.com} 1579655SAndreas.Sandberg@ARM.com 1589655SAndreas.Sandberg@ARM.com 1599655SAndreas.Sandberg@ARM.comPerfKvmTimer::PerfKvmTimer(PerfKvmCounter &ctr, 1609655SAndreas.Sandberg@ARM.com int signo, float hostFactor, Tick hostFreq) 1619655SAndreas.Sandberg@ARM.com : BaseKvmTimer(signo, hostFactor, hostFreq), 1629655SAndreas.Sandberg@ARM.com hwOverflow(ctr) 1639655SAndreas.Sandberg@ARM.com{ 1649655SAndreas.Sandberg@ARM.com hwOverflow.enableSignals(signo); 1659655SAndreas.Sandberg@ARM.com} 1669655SAndreas.Sandberg@ARM.com 1679655SAndreas.Sandberg@ARM.comPerfKvmTimer::~PerfKvmTimer() 1689655SAndreas.Sandberg@ARM.com{ 1699655SAndreas.Sandberg@ARM.com} 1709655SAndreas.Sandberg@ARM.com 1719655SAndreas.Sandberg@ARM.comvoid 1729655SAndreas.Sandberg@ARM.comPerfKvmTimer::arm(Tick ticks) 1739655SAndreas.Sandberg@ARM.com{ 1749655SAndreas.Sandberg@ARM.com hwOverflow.period(hostCycles(ticks)); 1759655SAndreas.Sandberg@ARM.com hwOverflow.refresh(1); 1769655SAndreas.Sandberg@ARM.com} 1779655SAndreas.Sandberg@ARM.com 1789655SAndreas.Sandberg@ARM.comvoid 1799655SAndreas.Sandberg@ARM.comPerfKvmTimer::disarm() 1809655SAndreas.Sandberg@ARM.com{ 1819655SAndreas.Sandberg@ARM.com hwOverflow.stop(); 1829655SAndreas.Sandberg@ARM.com} 1839655SAndreas.Sandberg@ARM.com 1849655SAndreas.Sandberg@ARM.comTick 1859655SAndreas.Sandberg@ARM.comPerfKvmTimer::calcResolution() 1869655SAndreas.Sandberg@ARM.com{ 1879881Sandreas@sandberg.pp.se return ticksFromHostCycles(MIN_HOST_CYCLES); 1889655SAndreas.Sandberg@ARM.com} 189