Skip to main content

If you don't have an IBM ID and password, register here.

By clicking Submit, you agree to the developerWorks terms of use.

The first time you sign into developerWorks, a profile is created for you. Select information in your developerWorks profile is displayed to the public, but you may edit the information at any time. Your first name, last name (unless you choose to hide them), and display name will accompany the content that you post.

All information submitted is secure.

The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerworks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

By clicking Submit, you agree to the developerWorks terms of use.

All information submitted is secure.

When microseconds matter

How the IBM High Resolution Time Stamp Facility accurately measures itty bits of time

W. Nathaniel Mills, III (wnm3@us.ibm.com), Senior Technical Staff Member, IBM Research
Nat joined IBM Research in 1996 after running a successful consulting and software development business for 10 years. His initial work in systems management lead to the development of WebSphere Studio Advanced Edition Page Detailer -- a tool to measure and display Web page download performance. You can contact him at wnm3@us.ibm.com. Nat would like to acknowledge valued contributions to the design and development of the IBM High Resolution Time Stamp Facility made by: LeRoy Krueger, David Wendt, and Ruey-Ching Chen. However, Nat accepts all responsibility for any errors.

Summary:  This article describes IBM's High Resolution Time Stamp Facility. Time stamps describe the occurrence of an event at a point in time. When time stamps share a common timing source, you can use them to measure durations of activities (Duration=T_end-T_start). Higher time stamp resolutions permit more accurate measurement of activity durations. Our team used the time stamp libraries to measure the duration of activities related to Web page response times. Taking performance measurements, and tracing and logging program activities, are common tasks for tuning applications to improve performance. This article explains how to use the library functions to understand and improve your applications. Where possible, development rationale and related experience are included to explain certain choices.

Date:  01 Apr 2002
Level:  Introductory

Activity:  11928 views
Comments:  

Mere seconds aren't enough

The resolution, or accuracy, you need with time stamps depends on what you want to accomplish. If you're measuring Web site traffic and counting content requests per hour, then capturing the time of each request to the second is plenty accurate. At most, one second's worth of requests might be attributed to the wrong hourly bucket. The error introduced to the report's accuracy is negligible on its utility. However, consider trying to use these same time stamps to measure how long it takes the Web server to respond to requests. The smallest positive duration we could measure is one second. Anything taking less time to service would be reported as having zero duration. Today's computers with multi-gigahertz CPUs, fast buses and memory, and content caches, are certainly capable of subsecond service times. Therefore, using time stamps with only a one second resolution isn't good enough.

Imagine wanting to measure the performance of the browser issuing requests. Before broadband, you might have gotten away using only seconds to measure how long, from start to finish, it took to retrieve a complex Web page. But, knowing that one page took 15 seconds and another took 5 doesn't offer much insight as to why the first page took 3 times as long to complete loading. There are many steps required to request, retrieve, and render a Web page. If we could measure the duration of each step then we could decompose the page response time to understand which steps had the most impact on the performance. The more steps you hope to measure, the more resolution you need to prevent reporting activity durations of zero time.

We see Web pages with hundreds of content pieces (such as images, style sheets, HTML frames, applets) arriving in only a few seconds across broadband connections. The activities in retrieving a single piece of content might involve several related steps:

  • Looking up the server IP address
  • Connecting to the server
  • Negotiating security
  • Requesting the content
  • Waiting for the server response
  • Receiving the content
  • Interpreting and rendering the content.

Depending on the current health of the network, its service provider(s), the design and size of the content, and the load on the server providing the content, any of the above activities can take abnormally long to complete. For transient problems, to understand the magnitude of the abnormally long activities it is helpful to have normal measurements to compare against. For example, occasionally we've seen pages normally retrieved in less than a second take 10 or more seconds due to misconfigured DNS servers (used to find the IP address of the server). In not-so-extreme situations, having normal DNS duration measurements helps determine if their current measurements are only slightly or extremely abnormal.

To measure all the subsecond activity durations, we needed to use the highest resolution time stamp possible. But, we also had another requirement to relate our time stamps to dates, and times of day, for reporting and archiving purposes. Here is where we met our first set of conflicts, which eventually lead us to develop the IBM High Resolution Time Stamp Facility (IBMTS).


Time-related Win32 APIs

The standard C libraries provided the time() method that returns the number of seconds since midnight, 1970 CUT. The ctime and gmtime routines allow conversion of these seconds to date (year, month, and day) and time of day (hours, minutes, and seconds). The ftime or _ftime methods improved on this concept, yielding more measurements in milliseconds (1/1000 second). However, in practice, ftime() milliseconds only reports its faction of seconds to the nearest 1/100th. So, with ftime() we can still resolve a time stamp to the date and time of day, as well as fractions of seconds to .01 resolution. In Linux and other *NIX systems, ftime() was replaced by the gettimeofday() method, which improves the resolution to microseconds (1/1000000 second). Unfortunately, gettimeofday() is not available in the Win32 APIs. So, to achieve higher resolution using Win32 we had to move to a different set of methods called timers.

The timer APIs work on elapsed times since a moving epoch. For example, timeGetTime() measures elapsed time in "system time" or milliseconds since the operating system was last started. We've seen it generate measurements to individual milliseconds, so it is better than ftime. However, to relate system times to calendar dates and times, you need to use the pair of methods GetSystemTimeAsFileTime and FileTimeAsSystemTime. Unfortunately, the resulting milliseconds accuracy is only 1/100th (similar to ftime). So, timeGetTime appears to be the best of these APIs but its output doesn't translate to calendar dates and times.

Luckily, Win32 provides the multimedia timer routines QueryPerformanceCounter and QueryPerformanceFrequency. They provide much better resolution than timeGetTime, approaching or exceeding microseconds accuracy. But, these APIs aren't without problems. They are not supported on all platforms, as they are based on hardware timers with special register support in the CPU. We have observed that the multimedia timers do not behave dependably on Win9x based operating systems. Though the QueryPerformanceFrequency returns a value (signaling these APIs are supported on the platform), the timers tend to drift from calendar time measurements. This is not a problem on WinNT, Win2K, or WinXP systems. Also, just like timeGetTime, the multimedia timer values aren't easily converted to calendar dates and times.

Another problem with both QueryPerformanceCounter and QueryPerformanceFrequency is they will wrap given enough elapsed time. For example, since timeGetTime returns an unsigned 32-bit value, it will wrap in just less than 50 days. The multimedia timers use 64-bit values and their wrap times vary from machine to machine. But, by addressing these issues and combining the timer functions with the time functions, we achieve the best of both worlds, and become immune to problems introduced by customers or time services that change the operating system's date and time.

Java developers might be interested to know the Date and Calendar classes in the Windows JVM implementations have time resolutions similar to ftime (for example, to 1/100th second).


The best of all worlds

The three basic concepts employed in IBMTS are:

  • Establish a base time that relates to calendar dates and times, and derive new time stamps based on elapsed time from this base (see Figure 1 below)
  • Anticipate wrap conditions in the elapsed time sufficiently in advance to adjust the base and avoid the wrap condition
  • Use the highest resolution timer available for the platform.

Addressing the last concept first, picking the best timer is not too difficult. QueryPerformanceFrequency is supposed to return 0 if it is not supported on a platform, otherwise it reports a converter used to transform the tick counts returned by QueryPerformanceCounter into seconds. So, if the operating system is not Win9x and we get a non-zero frequency, we use the multimedia timers; otherwise, we use timeGetTime to measure elapsed time.

The first time IBMTS is initialized, it establishes a time-of-day base time that can be used to generate calendar dates and times. This is simply the seconds returned by calling the time() method. It also records a base timer value from which elapsed time can be measured, as shown in Figure 1 below.


Figure 1. Time stamp calculation components
time stamp calculation

When an application needs a time stamp, we only need to:

  1. Call the timer function (such as QueryPerformanceCounter or timeGetTime, depending on the platform/OS) to be able to calculate the elapsed time from our base.
  2. Convert the elapsed time from microseconds to seconds by dividing by 1,000,000 and the remaining microsecond remainder (using a modulus of 1,000,000).
  3. Add the seconds to the time of day base value.
  4. Return the seconds and fraction thereof (microsecond remainder) to the caller.
int iRC = ibmts_calcTimeStamp(&ui32Seconds,&ui32MicroSeconds)

unsigned int ui32Seconds,ui32MicroSeconds=0;

A high-resolution time stamp could not be stored in a single 32-bit integer even if a new epoch was selected (say, from midnight 1/1/2001 UTC). If we hope to report microsecond accuracy in the time stamp, this would require enough digits to hold up to a million (0xF4240) values, thus leaving room for only a little over 4 thousand seconds. Because newer compilers support 64-bit unsigned integers, we opted to use 32 bits for the time of day (seconds), and 32 bits for the fractional portion of the time stamp, making it considerably easier for the time stamps to be formatted as dates and times using standard C, Java, and C++ calendar and date APIs.

Many unattended systems run for weeks at a stretch without being rebooted. On my IBM Thinkpad 600X, the QueryPerformanceFrequency returns 3579545 ticks per second. There are 64 bits to hold the QueryPerformanceCounter, but because we want to calculate microsecond accuracy, we can go for approximately 59 days = ((2^64 / (3579545*1000000))/86400) before wrapping back over our base. We didn't want to consume cycles by running a service to watch for wrap conditions, so opted instead to run in a dynamic link library (DLL) that is only active when called.

Because we have used our time stamping facility in frequently used applications and middleware, we could make the simplifying assumption that requests for time stamps will occur more than once within a wrap period. So, when we produce a time stamp we check the elapsed time against a threshold to see if we should move our base values. If we need to shift our base values forward in time, we use a named mutex to ensure only one program instance does the shifting (for example, if the mutex is busy, we know someone else is doing the shift). We don't need to protect the generation of the time stamp (readers) from the thread doing the shifting (writer) because it is extremely unlikely a context switch will occur during the six move instructions required to read the base values, and the added protection would add unnecessary execution time. Figure 2 below shows the related assembly code.

Line 139:     *pui32TODSeconds = pg_IBMTS_Data->ui32TODSeconds;
100011F9   mov         eax,dword ptr [pui32TODSeconds]
100011FC   mov         ecx,dword ptr [pg_IBMTS_Data (10003068)]
10001202   mov         edx,dword ptr [ecx+8]
10001205   mov         dword ptr [eax],edx
Line 140:     (*pliCounter).QuadPart = pg_IBMTS_Data->liTODCounter;
10001207   mov         eax,[pg_IBMTS_Data (10003068)]
1000120C   mov         ecx,dword ptr [pliCounter]
1000120F   mov         edx,dword ptr [eax+10h]
10001212   mov         dword ptr [ecx],edx
10001214   mov         eax,dword ptr [eax+14h]
10001217   mov         dword ptr [ecx+4],eax

To permit multiple processes to share a common timing source, we needed to make the time bases available through some means of shared storage. Initially, we'd used a named, global data segment in a DLL, with an anonymous shared mutex to signal updates. We later abandoned this approach because it was possible (though not advisable) to have several copies of the DLL stored on the same system in different directories. If multiple copies of the DLL were loaded, they would each have their own global data segment, producing time stamps from a different set of base timer values. While each process would see consistent time stamps, we could not correlate one process' time stamps with those of another process, and that contradicted one of our design goals.


Shared memory and a mutex

So, we switched to named shared memory (memory mapped files) and a named mutex. This allows processes to open access to previously-created shared memory to read the base timer values, and generate time stamps able to correlate with those generated from other processes using these base values. The shared memory and mutex remain viable until all instances of processes accessing them have closed. The first process requiring access to the time stamping facilities will [re]create the base timer values in shared memory and the shared mutex. It is only during this initial creation that the time of day clock is read, so all subsequent time stamps generated will be relative to this time of day. Should the PC's clock be changed while at least one process retains access to the shared facilities needed to generate time stamps, we will continue producing time stamps tied to our original clock setting, being immune to the changes. Only after all processes have relinquished access to the shared facilities and a new process causes the reinitialization of our base values will we resynchronize with the changed time of day clock.

Using time as a correlator between different time sources is fraught with difficulties and should only be used for loose correlation, as these sources can drift due to differences in timer hardware. For time-based correlation, it is essential that time stamps share a common timing source. In cases where exact ordering by time is required, we suggest using sequence numbers that are incremented in a protected manner (such as using the InterlockedIncrement APIs). To reduce the overhead of persisting these sequence numbers, you can store one every 1000 or so calls, and when restarting, simply retrieve the stored value and add 1000, or whatever modulus is being used, to create the new starting sequence number.

Time-sequential ordering is most easily done by sequence numbers rather than time stamps, but having high resolution time stamps can be very helpful when trying to relate different activities occurring on the same platform from different processes. For example, imagine instrumenting a Web browser to generate time stamped events when certain user actions and programmatic rendering activities occur. Also, consider instrumentation at the communications layer (such as in a Winsock Layered Service Provider (LSP)) that generates time stamped events when significant communication activities occur. When these time stamps are relative to the same base timer values, we can correctly determine durations for the activities relative to each other. Another example is coordinating activities performed by services on behalf of applications like DNS resolution in Windows 2000 Services.exe. Time stamps from the same timing source let us understand when DNS services have been provided for the browser during Web page retrievals.

A little bit of trouble

One implementation detail caused us some trouble. Because we'd used named shared memory and a named mutex, we needed to supply a value in their creation APIs for security attributes. Every book and example I'd ever seen passed NULL as the security attribute parameter, with the implication that allowing the default security was sufficient. Unfortunately, because our time stamping facilities were first used in a Winsock LSP that was started by the operating system, the time stamp DLL was loaded with its shared resources using the default security attributes of the operating system. Later, when we invoked a user application (such as a browser), it was unable to access the shared memory or mutex because its default security attribute was different than the operating system. Therefore, we had to update our code, as shown in Figure 3 below, to supply a very permissive security attribute instead of NULL when creating the shared memory and mutex, so any process attempting to create or access these resources would be granted permission.

// attempt to create (or gain access to) named shared memory
   SECURITY_ATTRIBUTES sa;
   sa.nLength = sizeof(sa);
   SECURITY_DESCRIPTOR sd;
   InitializeSecurityDescriptor(&sd,SECURITY_DESCRIPTOR_REVISION);
   SetSecurityDescriptorDacl(&sd,TRUE,NULL,FALSE);
   sa.lpSecurityDescriptor = &sd;
   sa.bInheritHandle = TRUE;
   if (IsWindows2KorLater()) {
      g_hShrMemMap = CreateFileMapping( ( HANDLE )0xFFFFFFFF,
         &sa, // typically shown as NULL in examples
         ( PAGE_READWRITE | SEC_COMMIT | SEC_NOCACHE ),
         0,
         i32Size,
         IBMTS_STR_GLOBAL_SHRMEM_NAME);
   } else {
      g_hShrMemMap = CreateFileMapping( ( HANDLE )0xFFFFFFFF,
         &sa, // typically shown as NULL in examples
         ( PAGE_READWRITE | SEC_COMMIT | SEC_NOCACHE ),
         0,
         i32Size,
         IBMTS_STR_SHRMEM_NAME);
   }

Once we had gotten everything working well in the C++ environment, we tested with the Apache 1.3.x Web server, which is based on C code. This introduced a few problems by having included the Windows.h header file in our ibmts.h, so we had to move the #includes and make other minor tweaks so our code could be called by Apache. Next, we added Java Native Interface (JNI) access so our Java-based programs could also be instrumented to share the same time stamping source and enjoy the high resolution timer access. Initially, the JNI code was added directly to the same DLL as was used for the C/C++ environment, which worked fine for specific application environments, but worked miserably for those systems that didn't have the Jave Runtime Environment (JRE) installed and were running only C/C++ based applications. So, the JNI code was pulled out into its own DLL (ibmtslink) so it could be added when Java access was required, but not a mandatory part of the installation.

Finally, we wanted the time stamping facilities to be pervasive and ideally to accommodate updates if needed, while requiring only one version to be installed (preferably in a common directory in the PATH like the Windows system directory). Therefore, we needed to support a version test API that was also visible using the properties inspection capabilities of the Windows Explorer. And, to let the size of the shared memory to expand to hold new information in future versions, we defined its structure so it references an array of undefined size to hold version-specific data. Though it's difficult to imagine what other data might need to be stored/shared (perhaps sequence number support?), this should allow for backward compatibility and for installation programs to test the installed version of the ibmts.dll, and only upgrade if the version is older than what is attempting to be installed.


Conclusion

By using a combination of the time of day clock and operating system timers, we developed a tool to generate high resolution time stamps in the Win32 environment from Java and C/C++ programs. The time stamps share a common source, so time based correlation is possible, even across processes running in the same platform. The time stamps are immune to problems introduced by customers or programs changing the time of day clock while instrumented programs are executing. By making these facilities available, we hope they become prevalent and promote common time stamping facilities across many different products.


Appendix A. Installing and using IBMTS

The ibmtsinst.exe file contains: the installer (setup.exe) that can be used by applications; several extra utility and test files; and documentation (see the link in Resources to download the code). If possible, run this self-extracting zip file and extract the contents into the c:\ directory, which will create a subdirectory named ibmts into which several files will be written. Click to see the content of the self-extracting download file.

The doc directory has information on using the installer (setup.exe). The media directory contains the files used by the installer. The installer/deinstaller takes into account version numbers and application dependencies on these libraries, so if your application is installed on a system where the IBMTS is already installed, it will do the appropriate thing. The utils directory contains testinstall.bat that will register a fake application named "XYZ" and install the various files relating to the IBMTS: ibmts.dll, ibmtslink.dll, ibmts.jar, ibmts.h, and ibmts.lib (described in more detail below). Once you have run testinstall.bat, you can check that these files have been installed in the Windows system directory. There are also two test files, test.exe and testjava.bat, used to verify that the install worked correctly. These two files are samples to test your installation (see sample output in Figure 4 and Figure 5 below). The ibmts.jar contains the JNI class needed to link Java applications to the ibmts.dll via ibmtslink.dll.

C:\ibmts\utils>test 10
IBM High Resolution Timestamp Test: Version=0x0001000000000005
Beginning loop for 10 iterations, using a 0 second delay each pass.
Expect to complete at 06:19:50 PM.
1019168389.013063 = 3CBF4685.00003307
1019168389.013087 = 3CBF4685.0000331F
1019168389.013108 = 3CBF4685.00003334
1019168389.013127 = 3CBF4685.00003347
1019168389.013148 = 3CBF4685.0000335C
1019168389.013168 = 3CBF4685.00003370
1019168389.013187 = 3CBF4685.00003383
1019168389.013208 = 3CBF4685.00003398
1019168389.013228 = 3CBF4685.000033AC
1019168389.013248 = 3CBF4685.000033C0

The ibmts.jar and ibmtslink.dll files provide the JNI access to the ibmts.dll methods. You can test by executing the com.ibm.ibmts.ibmtslink class (see sample output in Figure 6 below) or by simply running the testjava.bat utility.

(c) Copyright 2001-2002, International Business Machines Corporation.
Version=281474976710661
Process ID=2000
Thread ID=2192
Base Info:
        Frequency: 3579545
        Counter: 346245840857
        Seconds: 1019746312
        Microseconds: 96725156
Seconds=1019746312 Microseconds=63951
Microseconds since 1/1/70 epoch using Long=1019746312064341
Microseconds since 1/1/70 epoch using long=1019746312071667
Revised Base Info:
        Frequency: 3579545
        Counter: 346246112784
        Seconds: 1019746312
        Microseconds: 96725232
Seconds=1019746312 Microseconds=18257
Microseconds since 1/1/70 epoch=1019746312018274
Seconds=1019746312 Microseconds=25639
Microseconds since 1/1/70 epoch=1019746312025649
Seconds=1019746312 Microseconds=33816
Microseconds since 1/1/70 epoch=1019746312033829
Seconds=1019746312 Microseconds=40863
Microseconds since 1/1/70 epoch=1019746312040873
Seconds=1019746312 Microseconds=47788
Microseconds since 1/1/70 epoch=1019746312047797
Seconds=1019746312 Microseconds=54741
Microseconds since 1/1/70 epoch=1019746312054750
Seconds=1019746312 Microseconds=61659
Microseconds since 1/1/70 epoch=1019746312061668
Seconds=1019746312 Microseconds=69254
Microseconds since 1/1/70 epoch=1019746312069266
Seconds=1019746312 Microseconds=76570
Microseconds since 1/1/70 epoch=1019746312076588
Seconds=1019746312 Microseconds=84983
Microseconds since 1/1/70 epoch=1019746312084995

Results from 10 consecutive captures:
Microseconds since 1/1/70 epoch=1019746312092077
Microseconds since 1/1/70 epoch=1019746312092086
Microseconds since 1/1/70 epoch=1019746312092091
Microseconds since 1/1/70 epoch=1019746312092100
Microseconds since 1/1/70 epoch=1019746312092106
Microseconds since 1/1/70 epoch=1019746312092110
Microseconds since 1/1/70 epoch=1019746312092115
Microseconds since 1/1/70 epoch=1019746312092121
Microseconds since 1/1/70 epoch=1019746312092125
Microseconds since 1/1/70 epoch=1019746312092130

Note:  Version 281474976710661 == 0x0001000000000005 == 1.0.0.5

We have supplied an installer that can be run interactively or silently. There isn't much interaction -- just a splash bitmap showing we are installing, and you can alter this bitmap by changing the setup.bmp. We expect most applications using the IBMTS will run the silent installer. The readme.htm file documents how to do so, and an example is performed in the testinstall.bat utility (assuming you have installed IBMTS under the c:\ directory). To ensure all applications have access to the ibmts.dll and ibmtslink.dll we placed these in the Windows system directory. The installer also puts the corresponding development files (for C/C++: ibmts.lib, ibmts.h and for Java: ibmts.jar) in the system directory as well. While this is non-standard practice, we thought it best to keep the library, header file, and class that corresponds with the installed runtime DLLs together.


Appendix B. IBMTS Software Developer Kit

Part of the installer loads the software development kit (SDK) into the Windows system directory. The SDK comprises the ibmts.h and ibmts.lib files for C/C++ developers. Java developers can reference the ibmts.jar package "com.ibm.ibmts" by importing com.ibm.ibmts.ibmtslink in their programs. The ibmts.lib, ibmts.h, and ibmts.jar files are distributed with the IBMTS Installer (initiated by running Setup.exe).

Java APIs

Figure 6 shows code taken from the ibmtslink JNI class main method, which can be used to test the JNI interface. It shows how to create an ibmtslink object, then references its methods to generate time stamp information. It can be accessed by installing the ibmts.jar file (in the CLASSPATH), along with the ibmts.dll and ibmtslink.dll (in the PATH) and issuing the command java com.ibm.ibmts.ibmtslink.

public static void main(String [] args) {
      System.out.println(getCopyright());
      ibmtslink test = new ibmtslink();
      System.out.println("Version="+test.getLogicVersion());
      System.out.println("Process ID="+test.getOSProcessID());
      System.out.println("Thread ID="+test.getOSThreadID());
      long[] baseInfo = new long[4];
      
      baseInfo = test.getBaseInfo();
      System.out.println("Base Info:");
      System.out.println("\tFrequency: "+baseInfo[0]);
      System.out.println("\tCounter: "+baseInfo[1]);
      System.out.println("\tSeconds: "+baseInfo[2]);
      System.out.println("\tMicroseconds: "+baseInfo[3]);
      
      int [] ts = new int[2];
      test.calcTimeStamp(ts);
      Long lTS = test.getEpochMicrosecondsAsLong();
      System.out.println("Seconds="+ts[0]+" Microseconds="+ts[1]);
      System.out.println("Microseconds since 1/1/70 epoch using Long="+lTS);
      
      long lTSx = test.getEpochMicroseconds();
      System.out.println("Microseconds since 1/1/70 epoch using long="+lTSx);
      
      test.setBaseInfo();
      baseInfo = test.getBaseInfo();
      System.out.println("Revised Base Info:");
      System.out.println("\tFrequency: "+baseInfo[0]);
      System.out.println("\tCounter: "+baseInfo[1]);
      System.out.println("\tSeconds: "+baseInfo[2]);
      System.out.println("\tMicroseconds: "+baseInfo[3]);
      
      for (int i=0;i<10;i++) {
         test.calcTimeStamp(ts);
         lTSx = test.getEpochMicroseconds();
         System.out.println("Seconds="+ts[0]+" Microseconds="+ts[1]);
         System.out.println("Microseconds since 1/1/70 epoch="+lTSx);
      }
      long[] testValues = new long[10];
      for (int i=0;i<10;i++) {
         testValues[i] = test.getEpochMicroseconds();
      }
      System.out.println();
      System.out.println("Results from 10 consecutive captures:");
      for (int i=0;i<10;i++) {
         System.out.println("Microseconds since 1/1/70 epoch="+testValues[i]);
      }
      
   }

long getLogicVersion(void) returns the version of base timer values of the ibmts.dll being accessed. You can use it to determine if the ibmts.dll and ibmtslink.dll should be updated during installation. Otherwise, it is merely for informational purposes and possibly could be used to conditionally access new methods introduced in later versions of this code.

int getOSProcessID(void) returns the current process ID of the JVM executing the Java application or applet. This merely calls the getCurrentProcessId() method, which returns an unsigned value. Therefore, correlation will need to take comparison of signed and unsigned values into account when mixing information from C/C++ and Java sources.

int getOSThreadID(void) returns the current thread ID executing within the JVM executing the Java application or applet. This merely calls the getCurrentThreadId() method, which returns an unsigned value. So, correlation will need to take comparison of signed and unsigned values into account when mixing information from C/C++ and Java sources.

long[4] getBaseInfo() returns an array of four longs containing: frequency, counter, seconds and microseconds. Frequency and counter are the base timer values from the multimedia timer functions. Seconds and microseconds are the base time of day values.

int calcTimeStamp(int [2]) takes an array of two ints as input so it can return the time stamp values for seconds in the first cell (input[0]) and microseconds in the second cell (input[1]). IBMTS_SUCCESS (0) is returned in version 1.0.0.4, but reserved to enable error conditions to be returned. Note that it might be worthwhile to promote the seconds into a larger value as an unsigned quantity to let natural sorting to occur.

long getEpochMicroseconds(void) returns the time stamp as a long value by multiplying the seconds returned from calcTimeStamp by 1,000,000 and adding the microseconds as a convenience to programs wanting to manage a single value for the time stamp.

void setBaseInfo() resets the base values used for both the time of day and timers.

static final public int IBMTS_SUCCESS = 0 is available for comparison with the return value from calcTimeStamp().

Long getEpochMicrosecondsAsLong(void) returns the time stamp as a Long value by multiplying the seconds returned from calcTimeStamp() by 1,000,000 and adding the microseconds as a convenience to programs wanting to manage a single value for the time stamp.

String getCopyright(void) returns the copyright for this software as a String.

C/C++ APIs

unsigned __int64 ibmts_getVersion(void) returns the version of base timer values of the ibmts.dll being accessed. It can be used to determine if the ibmts.dll and ibmtslink.dll should be updated during installation. Otherwise, it is merely for informational purposes and possibly could be used to conditionally access new methods introduced in later versions of this code.

int ibmts_calcTimeStamp(unsigned int * pui32TODSeconds, unsigned int * pui32Microseconds) takes pointers to unsigned ints in order to return seconds since the epoch, and microseconds. IBMTS_SUCCESS (0) is returned in version 1.0.0.4, but reserved to enable error conditions to be returned.

int ibmts_getEpochMicroseconds(unsigned __int64 * pui64Epoch) returns the time stamp as microseconds since the midnight 1/1/70 CUT epoch in the passed pointer to an unsigned 64-bit integer. The value is calculated by multiplying the seconds returned from calcTimeStamp by 1,000,000 and adding the microseconds as a convenience to programs wanting to manage a single value for the time stamp. IBMTS_SUCCESS (0) is returned in version 1.0.0.4, but reserved to enable error conditions to be returned (if needed for future versions).


Resources

About the author

W. Nathaniel Mills, III

Nat joined IBM Research in 1996 after running a successful consulting and software development business for 10 years. His initial work in systems management lead to the development of WebSphere Studio Advanced Edition Page Detailer -- a tool to measure and display Web page download performance. You can contact him at wnm3@us.ibm.com. Nat would like to acknowledge valued contributions to the design and development of the IBM High Resolution Time Stamp Facility made by: LeRoy Krueger, David Wendt, and Ruey-Ching Chen. However, Nat accepts all responsibility for any errors.

Report abuse help

Report abuse

Thank you. This entry has been flagged for moderator attention.


Report abuse help

Report abuse

Report abuse submission failed. Please try again later.


developerWorks: Sign in

If you don't have an IBM ID and password, register here.


Forgot your IBM ID?


Forgot your password?
Change your password


By clicking Submit, you agree to the developerWorks terms of use.

 


The first time you sign into developerWorks, a profile is created for you. Select information in your developerWorks profile is displayed to the public, but you may edit the information at any time. Your first name, last name (unless you choose to hide them), and display name will accompany the content that you post.

Choose your display name

The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerWorks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

(Must be between 3 – 31 characters.)


By clicking Submit, you agree to the developerWorks terms of use.

 


Rate this article

Comments

Help: Update or add to My dW interests

What's this?

This little timesaver lets you update your My developerWorks profile with just one click! The general subject of this content (AIX and UNIX, Information Management, Lotus, Rational, Tivoli, WebSphere, Java, Linux, Open source, SOA and Web services, Web development, or XML) will be added to the interests section of your profile, if it's not there already. You only need to be logged in to My developerWorks.

And what's the point of adding your interests to your profile? That's how you find other users with the same interests as yours, and see what they're reading and contributing to the community. Your interests also help us recommend relevant developerWorks content to you.

View your My developerWorks profile

Return from help

Help: Remove from My dW interests

What's this?

Removing this interest does not alter your profile, but rather removes this piece of content from a list of all content for which you've indicated interest. In a future enhancement to My developerWorks, you'll be able to see a record of that content.

View your My developerWorks profile

Return from help

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=Sample IT projects
ArticleID=86663
ArticleTitle=When microseconds matter
publish-date=04012002
author1-email=wnm3@us.ibm.com
author1-email-cc=

Tags

Help
Use the search field to find all types of content in My developerWorks with that tag.

Use the slider bar to see more or fewer tags.

For articles in technology zones (such as Java technology, Linux, Open source, XML), Popular tags shows the top tags for all technology zones. For articles in product zones (such as Info Mgmt, Rational, WebSphere), Popular tags shows the top tags for just that product zone.

For articles in technology zones (such as Java technology, Linux, Open source, XML), My tags shows your tags for all technology zones. For articles in product zones (such as Info Mgmt, Rational, WebSphere), My tags shows your tags for just that product zone.

Use the search field to find all types of content in My developerWorks with that tag. Popular tags shows the top tags for this particular content zone (for example, Java technology, Linux, WebSphere). My tags shows your tags for this particular content zone (for example, Java technology, Linux, WebSphere).