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