RFR(M): 8028128: Add a type safe alternative for working with counter based data

Markus Gronlund markus.gronlund at oracle.com
Wed Nov 20 12:17:30 UTC 2013


Hi again,

I have created an updated webrev02 for the feedback I have gotten so far. In addition, I have added a few improvements to the original suggestion.

Updated Webrev02: http://cr.openjdk.java.net/~mgronlun/8028128/webrev02/ 
Original Webrev01: http://cr.openjdk.java.net/~mgronlun/8028128/webrev01/ 
Bug: https://bugs.openjdk.java.net/browse/JDK-8028128 

Thanks a lot for your help/patience in reviewing this large change - very much appreciated.

Cheers
Markus

Description of deltas/updates to Webrev02 compared to Webrev01:

// updates based on feedback

utilities/ticks.inline.hpp

// removed functions comparing against jlong(s)

- #63 inline bool operator==(const Ticks& lhs, jlong compare_value) {
- #64  return lhs.value() == compare_value;
- #65  }

- #89 inline bool operator!=(const Ticks& lhs, jlong compare_value) {
- #90  return lhs.value() != compare_value;
- #91 }

// updated to gt signs for operator<= functions
- #52 return !operator<(lhs, rhs);
+ #52 return !operator >(lhs, rhs);

- #98 return !operator<(lhs,rhs);
+ #98 return !operator>(lhs,rhs);

// thanks to Vitaly Davidovich.


share/vm/gc_implementation/gcTimer.hpp

// removed default parameter for report_gc_phase_* functions

- #114 void report_gc_phase_start(const char* name, const Ticks& time = Ticks::now());
+ #114 void report_gc_phase_start(const char* name, const Ticks& time);

- #115 void report_gc_phase_end(const Ticks& time = Ticks::now());
+ #115 void report_gc_phase_end(const Ticks& time);

- #145 void register_gc_phase_start(const char* name, const Ticks& time = Ticks::now());
+ #145 void register_gc_phase_start(const char* name, const Ticks& time);

- #146 void register_gc_phase_end(const Ticks& time = Ticks::now());
+ #146 void register_gc_phase_end(const Ticks& time);

// thanks to Per Liden.


//
//
//
//  Additional changes compared to webrev01 (delta)
//

webrev01 still allows a user to pass in a jlong (knowingly and/or unknowingly) for event.starttime() and event.endtime().
For example:

event.set_endtime(os::elapsed_counter()); // direct call using os::elapsed_counter()

This can be avoided by increasing encapsulation:

src/share/vm/trace/traceEvent.hpp:

set_starttime(const TracingTime& time) // remove default parameter and make protected
set_endtime(const TracingTime& time)   // remove default parameter and make protected

Now, the only visible external API for setting the start and/or endtime of an event is by passing a "Ticks" type (a compiler enforced constraint):

Using the same example as above, now if attempting to pass a jlong, like a direct call using os::elapsed_counter(), this now yields (at compile time):

>..\..\src\share\vm\gc_implementation\shared\gcTraceSend.cpp(63): error C2248: 'TraceEvent<T>::set_endtime' : cannot access protected member declared in class 'TraceEvent<T>'


In order to make these functions protected, i have also had to update the class loader events in SystemDictionary and ClassLoaderDataGraph:

share/vm/classfile/SystemDictionary.hpp:

// remove include file:
- #34 #include "trace/traceTime.hpp"

+ #80 forward declare class Ticks;


// update the signature
- #640 static void post_class_load_event(const TracingTime& start_time, instanceKlassHandle k,
                                    Handle initiating_loader);
                                    
+ #640 static void post_class_load_event(const Ticks& start_time, instanceKlassHandle k,
                                    Handle initiating_loader);



share/vm/classfile/SystemDictionary.cpp:

// added include files
+#58 #include "utilities/macros.hpp" 
+#59 #include "utilities/ticks.hpp" 

// removed old include file:
- #61 #include "trace/traceMacros.hpp"

// updated type
- #601 TracingTime class_load_start_time = Tracing::time();
+ #601 Ticks class_load_start_time = Ticks::now();

// updated type
- #1009 TracingTime class_load_start_time = Tracing::time();
+ #1009 Ticks class_load_start_time = Ticks::now();

// updated signature
- #2668 void SystemDictionary::post_class_load_event(TracingTime start_time, instanceKlassHandle k, Handle initiating_loader)
+ #2668 void SystemDictionary::post_class_load_event(const Ticks& start_time, instanceKlassHandle k, Handle initiating_loader)

// removed setting the endtime
- #2674 event.set_endtime(Tracing::time());


src/share/vm/classfile/classLoaderData.hpp:

// update include
- #36 #include "trace/traceTime.hpp"
+ #36 #include "utilities/ticks.hpp"

// updated type for _class_unload_time;
- #101 static TracingTime _class_unload_time;
+ #101 static Ticks _class_unload_time;


src/share/vm/classfile/classLoaderData.cpp:

+ #65 #include "utilities/macros.hpp"

// updated timestamp
- #757 _class_unload_time = Tracing::time();
+ #757 _class_unload_time = Ticks::now();

// updated type definition
- #835 TracingTime ClassLoaderDataGraph::_class_unload_time;
+ #835 Ticks ClassLoaderDataGraph::_class_unload_time;


src/share/vm/trace/traceEventClasses.xls:

// update the !INCLUDE_TRACE stubs
- #59 void set_starttime(jlong time) const {}
- #60 void set_endtime(jlong time) const {}

+ #59 void set_starttime(const Ticks& time) {}
+ #59 void set_endtime(const Ticks& time) {}


Thanks
Markus



>
> Greetings,
>
> Kindly asking for reviews for the following changeset:
>
> Webrev: http://cr.openjdk.java.net/~mgronlun/8028128/webrev01/
>
> Bug: https://bugs.openjdk.java.net/browse/JDK-8028128
>
> *Description:*
>
> Currently, when working with counter based data, the primary data type 
> representation in the VM are raw jlong's. jlong's are employed to 
> represent both:
>
> 1. a single instance in time, for example a "now" timestamp 2. a time 
> duration, a timespan, for example the duration between "now" - "then"
>
> Having a raw jlong type represent both of these shifts the 
> responsibility to the programmer to always ensure the correct validity 
> of the counter data, without any assistance either at compile time or 
> at runtime.
>
> The event based tracing framework relies heavily on counter based data 
> in order to keep track of time and timing related information and we 
> have seen counter data errors where the representation sent to the 
> tracing framework has submitted the wrong time, i.e. a timespan when a 
> time instant was expected and vice versa.
>
> We should therefore add an alternative to jlongs for representing 
> counter based data. We should enlist the help of the type system to 
> enforce the correct data types at compile time as well as introduce 
> strong runtime asserts in order to help with the correct usage of time 
> and to reduce the number of potential bugs.
>
> I will therefore add two new types in src/share/vm/utilities:
>
> 1. "Ticks" - represents a single counter based timestamp, a single 
> instance in time.
> 2. "Tickspan" - represents a counter based duration, a timespan,
>   between two "Ticks"
>
> Please see the added files:
>
> -src/share/vm/utilities/ticks.hpp
>
> -src/share/vm/utilities/ticks.inline.hpp
>
> -src/share/vm/utilities/ticks.cpp
>
> I have also updated some of the existing event based tracing "event 
> sites" to employ usage of these new types as well as updated a few 
> places in the event based tracing framework implementation to 
> accommodate these types.
>
> *Testing completed:*
>
> nsk.stress.testlist (UTE/Aurora)
>
> GC nightlies (Aurora)
>
> gc/gctests/* (UTE/Aurora)
>
> nsk.gc.testlist (UTE/Aurora)
>
> SpecJBB2013 (no regression)
>
> SpecJBB2005 (no regression)
>
> Kitchensink (locally Windows) runs for +> 9 days (still running.)
>
> Thanks in advance
> Markus
>



More information about the hotspot-gc-dev mailing list