timer.cc revision 10073
11689SN/A/* 22316SN/A * Copyright (c) 2012 ARM Limited 31689SN/A * All rights reserved 41689SN/A * 51689SN/A * The license below extends only to copyright in the software and shall 61689SN/A * not be construed as granting a license to any other intellectual 71689SN/A * property including but not limited to intellectual property relating 81689SN/A * to a hardware implementation of the functionality of the software 91689SN/A * licensed hereunder. You may use the software subject to the license 101689SN/A * terms below provided that you ensure that this notice is replicated 111689SN/A * unmodified and in its entirety in all distributions of the software, 121689SN/A * modified or unmodified, in source code or in binary form. 131689SN/A * 141689SN/A * Redistribution and use in source and binary forms, with or without 151689SN/A * modification, are permitted provided that the following conditions are 161689SN/A * met: redistributions of source code must retain the above copyright 171689SN/A * notice, this list of conditions and the following disclaimer; 181689SN/A * redistributions in binary form must reproduce the above copyright 191689SN/A * notice, this list of conditions and the following disclaimer in the 201689SN/A * documentation and/or other materials provided with the distribution; 211689SN/A * neither the name of the copyright holders nor the names of its 221689SN/A * contributors may be used to endorse or promote products derived from 231689SN/A * this software without specific prior written permission. 241689SN/A * 251689SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 261689SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 272665SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 282665SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 291689SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 301061SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 315953Ssaidi@eecs.umich.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 325596Sgblack@eecs.umich.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 331061SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 341061SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 355596Sgblack@eecs.umich.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 365596Sgblack@eecs.umich.edu * 375596Sgblack@eecs.umich.edu * Authors: Andreas Sandberg 385596Sgblack@eecs.umich.edu */ 395596Sgblack@eecs.umich.edu 404637SN/A#include <algorithm> 415596Sgblack@eecs.umich.edu#include <csignal> 424637SN/A#include <ctime> 434637SN/A#include <unistd.h> 444637SN/A#include <sys/syscall.h> 454637SN/A 464637SN/A#include "base/misc.hh" 475596Sgblack@eecs.umich.edu#include "base/trace.hh" 485596Sgblack@eecs.umich.edu#include "cpu/kvm/timer.hh" 495596Sgblack@eecs.umich.edu#include "debug/KvmTimer.hh" 505596Sgblack@eecs.umich.edu 515596Sgblack@eecs.umich.edu/* According to timer_create(2), the value SIGEV_THREAD_ID can be used 524637SN/A * to specify which thread a timer signal gets delivered to. According 535596Sgblack@eecs.umich.edu * to the man page, the member sigev_notify_thread is used to specify 541061SN/A * the TID. This member is currently not defined by default in 552292SN/A * siginfo.h on x86, so we define it here as a workaround. 561061SN/A */ 571061SN/A#ifndef sigev_notify_thread_id 581061SN/A#define sigev_notify_thread_id _sigev_un._tid 595596Sgblack@eecs.umich.edu#endif 601464SN/A 611061SN/Astatic pid_t 622292SN/Agettid() 632292SN/A{ 642292SN/A return syscall(__NR_gettid); 652292SN/A} 662292SN/A 675596Sgblack@eecs.umich.edu/** 682292SN/A * Minimum number of cycles that a host can spend in a KVM call (used 691464SN/A * to calculate the resolution of some timers). 701464SN/A * 711464SN/A * The value of this constant is a bit arbitrary, but in practice, we 722292SN/A * can't really do anything useful in less than ~1000 cycles. 733782SN/A */ 741464SN/Astatic const uint64_t MIN_HOST_CYCLES = 1000; 751464SN/A 762292SN/APosixKvmTimer::PosixKvmTimer(int signo, clockid_t clockID, 773782SN/A float hostFactor, Tick hostFreq) 782292SN/A : BaseKvmTimer(signo, hostFactor, hostFreq), 791464SN/A clockID(clockID) 801061SN/A{ 811061SN/A struct sigevent sev; 822292SN/A 832292SN/A sev.sigev_notify = SIGEV_THREAD_ID; 845596Sgblack@eecs.umich.edu sev.sigev_signo = signo; 852292SN/A sev.sigev_notify_thread_id = gettid(); 862348SN/A sev.sigev_value.sival_ptr = NULL; 872680SN/A 882348SN/A while (timer_create(clockID, &sev, &timer) == -1) { 892680SN/A if (errno != EAGAIN) 902292SN/A panic("timer_create: %i", errno); 912292SN/A } 922292SN/A} 932292SN/A 942292SN/APosixKvmTimer::~PosixKvmTimer() 952292SN/A{ 962292SN/A timer_delete(timer); 972292SN/A} 982292SN/A 992292SN/Avoid 1002292SN/APosixKvmTimer::arm(Tick ticks) 1012292SN/A{ 1025596Sgblack@eecs.umich.edu struct itimerspec ts; 1032292SN/A memset(&ts, 0, sizeof(ts)); 1042348SN/A 1052680SN/A ts.it_interval.tv_sec = 0; 1062348SN/A ts.it_interval.tv_nsec = 0; 1072680SN/A ts.it_value.tv_sec = hostNs(ticks) / 1000000000ULL; 1082292SN/A ts.it_value.tv_nsec = hostNs(ticks) % 1000000000ULL; 1092292SN/A 1102292SN/A assert(ts.it_value.tv_nsec > 0 || ts.it_value.tv_sec > 0); 1112292SN/A 1122292SN/A DPRINTF(KvmTimer, "Arming POSIX timer: %i ticks (%is%ins)\n", 1132292SN/A ticks, ts.it_value.tv_sec, ts.it_value.tv_nsec); 1142292SN/A 1152292SN/A if (timer_settime(timer, 0, &ts, NULL) == -1) 1162292SN/A panic("PosixKvmTimer: Failed to arm timer\n"); 1172292SN/A} 1182292SN/A 1192292SN/Avoid 1205596Sgblack@eecs.umich.eduPosixKvmTimer::disarm() 1212292SN/A{ 1222790SN/A struct itimerspec ts; 1232292SN/A memset(&ts, 0, sizeof(ts)); 1242292SN/A 1252292SN/A DPRINTF(KvmTimer, "Disarming POSIX timer\n"); 1262292SN/A 1271858SN/A if (timer_settime(timer, 0, &ts, NULL) == -1) 1281061SN/A panic("PosixKvmTimer: Failed to disarm timer\n"); 1295702Ssaidi@eecs.umich.edu} 1305702Ssaidi@eecs.umich.edu 1315702Ssaidi@eecs.umich.eduTick 1325702Ssaidi@eecs.umich.eduPosixKvmTimer::calcResolution() 1335702Ssaidi@eecs.umich.edu{ 1345702Ssaidi@eecs.umich.edu struct timespec ts; 1355702Ssaidi@eecs.umich.edu 1365702Ssaidi@eecs.umich.edu if (clock_getres(clockID, &ts) == -1) 1375702Ssaidi@eecs.umich.edu panic("PosixKvmTimer: Failed to get timer resolution\n"); 1385702Ssaidi@eecs.umich.edu 1395702Ssaidi@eecs.umich.edu const uint64_t res_ns(ts.tv_sec * 1000000000ULL + ts.tv_nsec); 1405953Ssaidi@eecs.umich.edu // We preferrably want ticksFromHostNs() to calculate the the 1415953Ssaidi@eecs.umich.edu // ceiling rather than truncating the value. However, there are 1425953Ssaidi@eecs.umich.edu // other cases where truncating is fine, so we just add 1 here to 1435953Ssaidi@eecs.umich.edu // make sure that the actual resolution is strictly less than what 1445702Ssaidi@eecs.umich.edu // we return. We could get all kinds of nasty behavior if 1455702Ssaidi@eecs.umich.edu // arm(resolution) is called and the resulting time is 0 (which 1465702Ssaidi@eecs.umich.edu // could happen if we truncate the results and the resolution is 1475702Ssaidi@eecs.umich.edu // 1ns). 1485702Ssaidi@eecs.umich.edu const Tick resolution(ticksFromHostNs(res_ns) + 1); 1495702Ssaidi@eecs.umich.edu // It might not make sense to enter into KVM for less than a 1505702Ssaidi@eecs.umich.edu // certain number of host cycles. In some systems (e.g., Linux) 1515702Ssaidi@eecs.umich.edu // the resolution of the timer we use is 1ns (a few cycles on most 1525702Ssaidi@eecs.umich.edu // CPUs), which isn't very useful. 1535702Ssaidi@eecs.umich.edu const Tick min_cycles(ticksFromHostCycles(MIN_HOST_CYCLES)); 1545702Ssaidi@eecs.umich.edu 1551061SN/A return std::max(resolution, min_cycles); 1565596Sgblack@eecs.umich.edu} 1571061SN/A 1582292SN/A 1591061SN/APerfKvmTimer::PerfKvmTimer(PerfKvmCounter &ctr, 1605702Ssaidi@eecs.umich.edu int signo, float hostFactor, Tick hostFreq) 1615702Ssaidi@eecs.umich.edu : BaseKvmTimer(signo, hostFactor, hostFreq), 1625702Ssaidi@eecs.umich.edu hwOverflow(ctr) 1635702Ssaidi@eecs.umich.edu{ 1645702Ssaidi@eecs.umich.edu hwOverflow.enableSignals(signo); 1655702Ssaidi@eecs.umich.edu} 1665702Ssaidi@eecs.umich.edu 1675702Ssaidi@eecs.umich.eduPerfKvmTimer::~PerfKvmTimer() 1685702Ssaidi@eecs.umich.edu{ 1695702Ssaidi@eecs.umich.edu} 1701061SN/A 1711061SN/Avoid 1721061SN/APerfKvmTimer::arm(Tick ticks) 1735596Sgblack@eecs.umich.edu{ 1741061SN/A hwOverflow.period(hostCycles(ticks)); 1755556SN/A hwOverflow.refresh(1); 1765556SN/A} 1775556SN/A 1785556SN/Avoid 1792669SN/APerfKvmTimer::disarm() 1805556SN/A{ 1815556SN/A hwOverflow.stop(); 1825556SN/A} 1835556SN/A 1841061SN/ATick 1851061SN/APerfKvmTimer::calcResolution() 1861061SN/A{ 187 return ticksFromHostCycles(MIN_HOST_CYCLES); 188} 189