note description: "Utility functions for the profiling application" author: "Comerge AG, DR" date: "$Date$" revision: "$Revision$" class PROFILING_UTILS inherit DT_SHARED_SYSTEM_CLOCK feature -- Utility compute_mean (a_values: ARRAY[INTEGER_64]): REAL_64 is -- compute the mean of the values in the list require valid_input: a_values /= Void and then not a_values.is_empty local i: INTEGER sum: INTEGER_64 do sum := 0 from i := 1 until i > a_values.count loop sum := sum + a_values.item (i) i := i + 1 end Result := sum / a_values.count.to_real end compute_timestamp_now: INTEGER_64 is -- fancy routine to compute a timestamp in miliseconds precision -- (this is different to the regular unix timestamp which is measured in seconds) local -- seconds: NATURAL_32 microseconds: NATURAL_32 tmp_sec: INTEGER -- total_microseconds: NATURAL_64 do current_seconds_and_microseconds($tmp_sec, $microseconds) -- -- normalize -- total_microseconds := tmp_sec.as_natural_64 * 1000000 + microseconds -- -- convert to miliseconds -- Result := (total_microseconds / 1000.0).truncated_to_integer_64 -- normalize Result := (tmp_sec.as_integer_64 * 1000) + (microseconds / 1000.0).truncated_to_integer_64 end print_list (a_list: DS_ARRAYED_LIST [ANY]) is -- mighty method to pretty print a list require valid_list: a_list /= Void local l_pretty: STRING do create l_pretty.make_empty from a_list.start until a_list.off loop l_pretty.append(a_list.item_for_iteration.out) l_pretty.append(", ") a_list.forth end l_pretty.remove_tail (2) print (l_pretty + "%N") end min_list (a_list: DS_ARRAYED_LIST [INTEGER_64]): INTEGER_64 is -- extracts the minimum value from the list local l_sorter: DS_QUICK_SORTER [INTEGER_64] l_comparator: KL_COMPARABLE_COMPARATOR [INTEGER_64] l_list: DS_ARRAYED_LIST [INTEGER_64] do create l_list.make_from_linear (a_list) create l_comparator.make create l_sorter.make (l_comparator) l_list.sort (l_sorter) Result := l_list.item (1) end remove_min (a_list: DS_ARRAYED_LIST [INTEGER_64]): INTEGER_64 is -- removes the smallest element in the list and returns the element local min_index, index: INTEGER do from min_index := 1 index := 1 until index > a_list.count loop if a_list.item (index) < a_list.item (min_index) then min_index := index end index := index + 1 end a_list.remove (min_index) Result := a_list.item (min_index) end remove_max (a_list: DS_ARRAYED_LIST [INTEGER_64]): INTEGER_64 is -- Removes the largest element in the list and returns the element local max_index, index: INTEGER do from max_index := 1 index := 1 until index > a_list.count loop if a_list.item (index) > a_list.item (max_index) then max_index := index end index := index + 1 end a_list.remove (max_index) Result := a_list.item (max_index) end max_list (a_list: DS_ARRAYED_LIST [INTEGER_64]): INTEGER_64 is -- extracts the maximum value from the list local l_sorter: DS_QUICK_SORTER [INTEGER_64] l_comparator: KL_COMPARABLE_COMPARATOR [INTEGER_64] l_list: DS_ARRAYED_LIST [INTEGER_64] do create l_list.make_from_linear (a_list) create l_comparator.make create l_sorter.make (l_comparator) l_list.sort (l_sorter) Result := l_list.last end create_message_payload(a_count: INTEGER): STRING is -- Creates the message payload with `a_count' characters do Result := random_string (a_count) if Result.count /= a_count then print ("ERROR: Length of the msg payload deviates from the specified length: " + Result.count.out + " instead of " + a_count.out) end end feature -- Messaging serialize_timestamp_list (a_list: DS_ARRAYED_LIST [INTEGER_64]): DS_ARRAYED_LIST [A_STRING_VALUE] is -- converts the list of timestamps into the format used for the profiling results request reply message -- (we need this because INTEGER_64 is not supported by Aranea) require not_void: a_list /= Void do create Result.make (a_list.count) from a_list.start until a_list.off loop Result.force_last (a_list.item_for_iteration.out) a_list.forth end ensure same_size: a_list.count = Result.count end deserialize_timestamp_list (a_list: A_SEQUENCE_VALUE [A_STRING_VALUE]): DS_ARRAYED_LIST [INTEGER_64] is -- Deserialize timestamps retrieved from the profiling results request reply message -- (we need this because INTEGER_64 is not supported by Aranea) require not_void: a_list /= Void local l_list: DS_ARRAYED_LIST [A_STRING_VALUE] do l_list := a_list.sequence create Result.make (l_list.count) from l_list.start until l_list.off loop Result.force_last (l_list.item_for_iteration.value.to_integer_64) l_list.forth end ensure same_size: a_list.sequence.count = Result.count end feature {NONE} -- Random char_z: CHARACTER is -- 'Z' character once Result := 'Z' end char_a: CHARACTER is -- 'A' character once Result := 'A' end dev_random_file: STRING is "/dev/urandom" modulo_range: INTEGER is -- The modulo divisor once Result := char_z.code - char_a.code + 1 end to_alphabetic_character (a_character: CHARACTER): CHARACTER is -- Transform random character to character from the range A-Z. do Result := ((a_character.code \\ modulo_range) + char_a.code).to_character_8 ensure result_in_range: Result.code >= char_a.code and Result.code <= char_z.code end random_string (a_string_length: INTEGER_32): STRING is -- Generate random string of length `a_string_length'. -- copied from CO_RANDOM_GENERATOR require length_ok: a_string_length > 0 local file: PLAIN_TEXT_FILE i: INTEGER unfiltered_string: STRING do -- read from random device create file.make_open_read(dev_random_file) file.read_stream (a_string_length) file.close -- conversion to alphabetic string create unfiltered_string.make_from_string (file.last_string) create Result.make_empty from i := 1 until i > a_string_length loop Result.append_character (to_alphabetic_character(unfiltered_string.item(i))) i := i + 1 end ensure result_not_void: Result /= Void result_proper_len: Result.count = a_string_length end feature {NONE} -- implementation current_seconds_and_microseconds(sec: TYPED_POINTER[INTEGER]; msec: TYPED_POINTER[NATURAL_32]) is -- Get the current time, starting at January 1, 1970. external "C inline use " alias "[ { // C local variable struct timeval tp; gettimeofday(&tp, 0); *$sec = tp.tv_sec; *$msec = tp.tv_usec; } ]" end -- compute_timestamp_now: INTEGER_64 is -- -- compute a unix timestamp the eiffel way -- local -- l_now: DT_DATE_TIME -- l_duration: DT_DATE_TIME_DURATION -- do -- -- make sure that we are using utc time everywhere -- l_now := utc_system_clock.date_time_now -- l_duration := l_now - unix_origin -- l_duration := l_duration.to_canonical (unix_origin) -- Result := l_duration.millisecond -- end -- unix_origin: DT_DATE_TIME is -- -- base date for unix time stamps -- once -- create Result.make_precise (1970, 1, 1, 0, 0, 0, 0) -- end end