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