![]() |
libzmq master
The Intelligent Transport Layer
|
00001 /* 00002 Copyright (c) 2010-2011 250bpm s.r.o. 00003 Copyright (c) 2010-2011 Other contributors as noted in the AUTHORS file 00004 00005 This file is part of 0MQ. 00006 00007 0MQ is free software; you can redistribute it and/or modify it under 00008 the terms of the GNU Lesser General Public License as published by 00009 the Free Software Foundation; either version 3 of the License, or 00010 (at your option) any later version. 00011 00012 0MQ is distributed in the hope that it will be useful, 00013 but WITHOUT ANY WARRANTY; without even the implied warranty of 00014 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00015 GNU Lesser General Public License for more details. 00016 00017 You should have received a copy of the GNU Lesser General Public License 00018 along with this program. If not, see <http://www.gnu.org/licenses/>. 00019 */ 00020 00021 #include "clock.hpp" 00022 #include "platform.hpp" 00023 #include "likely.hpp" 00024 #include "config.hpp" 00025 #include "err.hpp" 00026 00027 #include <stddef.h> 00028 00029 #if defined _MSC_VER 00030 #include <intrin.h> 00031 #endif 00032 00033 #if !defined ZMQ_HAVE_WINDOWS 00034 #include <sys/time.h> 00035 #endif 00036 00037 zmq::clock_t::clock_t () : 00038 last_tsc (rdtsc ()), 00039 last_time (now_us () / 1000) 00040 { 00041 } 00042 00043 zmq::clock_t::~clock_t () 00044 { 00045 } 00046 00047 uint64_t zmq::clock_t::now_us () 00048 { 00049 #if defined ZMQ_HAVE_WINDOWS 00050 00051 // Get the high resolution counter's accuracy. 00052 LARGE_INTEGER ticksPerSecond; 00053 QueryPerformanceFrequency (&ticksPerSecond); 00054 00055 // What time is it? 00056 LARGE_INTEGER tick; 00057 QueryPerformanceCounter (&tick); 00058 00059 // Convert the tick number into the number of seconds 00060 // since the system was started. 00061 double ticks_div = (double) (ticksPerSecond.QuadPart / 1000000); 00062 return (uint64_t) (tick.QuadPart / ticks_div); 00063 00064 #else 00065 00066 // Use POSIX gettimeofday function to get precise time. 00067 struct timeval tv; 00068 int rc = gettimeofday (&tv, NULL); 00069 errno_assert (rc == 0); 00070 return (tv.tv_sec * (uint64_t) 1000000 + tv.tv_usec); 00071 00072 #endif 00073 } 00074 00075 uint64_t zmq::clock_t::now_ms () 00076 { 00077 uint64_t tsc = rdtsc (); 00078 00079 // If TSC is not supported, get precise time and chop off the microseconds. 00080 if (!tsc) 00081 return now_us () / 1000; 00082 00083 // If TSC haven't jumped back (in case of migration to a different 00084 // CPU core) and if not too much time elapsed since last measurement, 00085 // we can return cached time value. 00086 if (likely (tsc - last_tsc <= (clock_precision / 2) && tsc >= last_tsc)) 00087 return last_time; 00088 00089 last_tsc = tsc; 00090 last_time = now_us () / 1000; 00091 return last_time; 00092 } 00093 00094 uint64_t zmq::clock_t::rdtsc () 00095 { 00096 #if (defined _MSC_VER && (defined _M_IX86 || defined _M_X64)) 00097 return __rdtsc (); 00098 #elif (defined __GNUC__ && (defined __i386__ || defined __x86_64__)) 00099 uint32_t low, high; 00100 __asm__ volatile ("rdtsc" : "=a" (low), "=d" (high)); 00101 return (uint64_t) high << 32 | low; 00102 #elif (defined __SUNPRO_CC && (__SUNPRO_CC >= 0x5100) && (defined __i386 || \ 00103 defined __amd64 || defined __x86_64)) 00104 union { 00105 uint64_t u64val; 00106 uint32_t u32val [2]; 00107 } tsc; 00108 asm("rdtsc" : "=a" (tsc.u32val [0]), "=d" (tsc.u32val [1])); 00109 return tsc.u64val; 00110 #elif defined(__s390__) 00111 uint64_t tsc; 00112 asm("\tstck\t%0\n" : "=Q" (tsc) : : "cc"); 00113 tsc >>= 12; /* convert to microseconds just to be consistent */ 00114 return(tsc); 00115 #else 00116 return 0; 00117 #endif 00118 }