From 6a8faff3cdd93c5289278cc8d8eb93492176e6fc Mon Sep 17 00:00:00 2001 From: Viktor Kreschenski Date: Wed, 9 Dec 2020 13:25:34 +0100 Subject: [PATCH 1/4] Scenario generator moving objects --- gen_scenarios/gen_scenario.py | 125 ++++++++++++++++++++++++++++++++++ 1 file changed, 125 insertions(+) create mode 100644 gen_scenarios/gen_scenario.py diff --git a/gen_scenarios/gen_scenario.py b/gen_scenarios/gen_scenario.py new file mode 100644 index 000000000..6f9641936 --- /dev/null +++ b/gen_scenarios/gen_scenario.py @@ -0,0 +1,125 @@ +from osi3.osi_sensorview_pb2 import SensorView +import struct +import argparse +import os +import random + +""" +This program generates currently random scenarios with predefined message count and moving object count. + +Example usage: + python gen_scenario.py --output "movingobject" --message 10 --moving_objects 5 --random + python gen_scenario.py --output "movingobject" --messages 100 --moving_objects 100 --random +""" + + +def command_line_arguments(): + """ Define and handle command line interface """ + + parser = argparse.ArgumentParser( + description="Generate OSI scenarios.", prog="gen_scenario" + ) + parser.add_argument( + "--output", + "-o", + help="Name of the output file.", + default="output.osi", + type=str, + ) + parser.add_argument( + "--messages", + "-m", + help="Path to the file with serialized data.", + default=1, + type=int, + ) + parser.add_argument( + "--moving_objects", + "-mo", + help="Count of the movin objects.", + default=0, + type=int, + required=False, + ) + parser.add_argument( + "--random", + "-r", + help="Random placement of objects into the world.", + default=True, + required=False, + action="store_true", + ) + + return parser.parse_args() + + +def main(): + # Handling of command line arguments + args = command_line_arguments() + message_count = args.messages + moving_objects_count = args.moving_objects + use_random = args.random + output = args.output + + moving_objects_dict = {} + + """Initialize SensorView""" + f = open(f"sv_312_320_{moving_objects_count}_{output}.osi", "ab") + sensorview = SensorView() + + sv_ground_truth = sensorview.global_ground_truth + sv_ground_truth.version.version_major = 3 + sv_ground_truth.version.version_minor = 1 + sv_ground_truth.version.version_patch = 2 + + sv_ground_truth.timestamp.seconds = 0 + sv_ground_truth.timestamp.nanos = 0 + + # Create moving object dictionary + for mo in range(args.moving_objects): + moving_object = sv_ground_truth.moving_object.add() + moving_object.id.value = mo + + moving_object.base.position.x = random.randint(0, 100) if use_random else 0.0 + moving_object.base.position.y = random.randint(0, 100) if use_random else 0.0 + moving_object.base.position.z = random.randint(0, 100) if use_random else 0.0 + + # Vehicle dimension + moving_object.base.dimension.length = 5 + moving_object.base.dimension.width = 2 + moving_object.base.dimension.height = 1 + + # Classification type + moving_object.vehicle_classification.type = 2 + + # Direction + moving_object.base.orientation.roll = 0.0 + moving_object.base.orientation.pitch = 0.0 + moving_object.base.orientation.yaw = 0.0 + + # Save in dictionary + moving_objects_dict[mo] = moving_object + + # Generate OSI messages + for message_num in range(args.messages): + + # Increment the time by one second + sv_ground_truth.timestamp.seconds += 1 + sv_ground_truth.timestamp.nanos = 0 + + for mo_key, mo in moving_objects_dict.items(): + + mo.base.position.x += 1 + mo.base.position.y = mo.base.position.y + mo.base.position.z = mo.base.position.z + + """Serialize""" + bytes_buffer = sensorview.SerializeToString() + f.write(struct.pack(" Date: Thu, 14 Jan 2021 10:47:49 +0100 Subject: [PATCH 2/4] Add virtual folder ignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index de104d3fd..f2a0010ae 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,7 @@ dist/ doc/html doc/latex osi/ +venv/ # Specific extensions *.egg-info From 00a2f92b65b0253be4b4266e3c5edac76fc3db57 Mon Sep 17 00:00:00 2001 From: Viktor Kreschenski Date: Thu, 14 Jan 2021 11:55:07 +0100 Subject: [PATCH 3/4] Added stationary objects --- gen_scenarios/gen_scenario.py | 45 ++++++++++++++++++++++++++++++++--- 1 file changed, 42 insertions(+), 3 deletions(-) diff --git a/gen_scenarios/gen_scenario.py b/gen_scenarios/gen_scenario.py index 6f9641936..62b36a825 100644 --- a/gen_scenarios/gen_scenario.py +++ b/gen_scenarios/gen_scenario.py @@ -6,6 +6,7 @@ """ This program generates currently random scenarios with predefined message count and moving object count. +This scenario generator can also be used to test the performance of osi-visualizer. Example usage: python gen_scenario.py --output "movingobject" --message 10 --moving_objects 5 --random @@ -41,6 +42,14 @@ def command_line_arguments(): type=int, required=False, ) + parser.add_argument( + "--stationary_objects", + "-so", + help="Count of the stationary objects.", + default=0, + type=int, + required=False, + ) parser.add_argument( "--random", "-r", @@ -62,6 +71,7 @@ def main(): output = args.output moving_objects_dict = {} + stationary_objects_dict = {} """Initialize SensorView""" f = open(f"sv_312_320_{moving_objects_count}_{output}.osi", "ab") @@ -100,19 +110,48 @@ def main(): # Save in dictionary moving_objects_dict[mo] = moving_object + # Create stationary object dictionary + for so in range(args.stationary_objects): + stationary_object = sv_ground_truth.stationary_object.add() + stationary_object.id.value = so + + stationary_object.base.position.x = random.randint(0, 10000) if use_random else 0.0 + stationary_object.base.position.y = random.randint(0, 100) if use_random else 0.0 + stationary_object.base.position.z = random.randint(0, 100) if use_random else 0.0 + + # Object dimension + stationary_object.base.dimension.length = 5 + stationary_object.base.dimension.width = 5 + stationary_object.base.dimension.height = 5 + + # Direction + stationary_object.base.orientation.roll = 0.0 + stationary_object.base.orientation.pitch = 0.0 + stationary_object.base.orientation.yaw = 0.0 + + # Save in dictionary + stationary_objects_dict[so] = stationary_object + # Generate OSI messages + nano_increment = 10000000 for message_num in range(args.messages): # Increment the time by one second - sv_ground_truth.timestamp.seconds += 1 - sv_ground_truth.timestamp.nanos = 0 + if sv_ground_truth.timestamp.nanos > 1000000000: + sv_ground_truth.timestamp.seconds += 1 + sv_ground_truth.timestamp.nanos = 0 + sv_ground_truth.timestamp.nanos += nano_increment for mo_key, mo in moving_objects_dict.items(): - mo.base.position.x += 1 + mo.base.position.x += 0.5 mo.base.position.y = mo.base.position.y mo.base.position.z = mo.base.position.z + mo.base.orientation.yaw += 0.1 + mo.base.orientation.roll += 0.1 + mo.base.orientation.pitch += 0.1 + """Serialize""" bytes_buffer = sensorview.SerializeToString() f.write(struct.pack(" Date: Tue, 23 Feb 2021 10:30:31 +0100 Subject: [PATCH 4/4] Performance measurement tool of the GroudTrurh/MovingObject combination in C++ and Python. Signed-off-by: Georg Seifert --- gen_scenarios/performace/clock.h | 46 +++++ gen_scenarios/performace/performance.cpp | 208 +++++++++++++++++++++++ gen_scenarios/performace/performance.py | 113 ++++++++++++ 3 files changed, 367 insertions(+) create mode 100644 gen_scenarios/performace/clock.h create mode 100644 gen_scenarios/performace/performance.cpp create mode 100644 gen_scenarios/performace/performance.py diff --git a/gen_scenarios/performace/clock.h b/gen_scenarios/performace/clock.h new file mode 100644 index 000000000..fb9321f52 --- /dev/null +++ b/gen_scenarios/performace/clock.h @@ -0,0 +1,46 @@ +// \file clock.h +// \brief Platform independent time stamp +// +// \author Georg Seifert +// \version 0.1 +// \date 2021 +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, you can obtain one at http://mozilla.org/MPL/2.0/ +// + +#ifndef HIGH_PRECITION_CLOCK_H +#define HIGH_PRECITION_CLOCK_H + +#ifdef __unix__ + #include + #include +#elif _WIN32 + #include + #include +#else + #error "OS not supported!" +#endif + +// \brief Time stamp with nanoseconds resolution +// +// \return monotonic time stamp +// +static inline uint64_t clock_get_ns() +{ +#ifdef __unix__ + struct timespec ts; + clock_gettime(CLOCK_MONOTONIC, &ts); + return ((uint64_t)(ts.tv_sec * 1000000000)) + (uint64_t)ts.tv_nsec; +#elif _WIN32 + LARGE_INTEGER ts, freq; + QueryPerformanceFrequency(&freq); + QueryPerformanceCounter(&ts); + return ((uint64_t)(ts.QuadPart * 1000000000)) / (uint64_t)freq.QuadPart; +#else + #error "OS not supported!" +#endif +} + +#endif // HIGH_PRECITION_CLOCK_H diff --git a/gen_scenarios/performace/performance.cpp b/gen_scenarios/performace/performance.cpp new file mode 100644 index 000000000..d6c858c0b --- /dev/null +++ b/gen_scenarios/performace/performance.cpp @@ -0,0 +1,208 @@ +// \file performance.cpp +// \brief Simple performance evaluation example +// +// Simple test application, which measures the execution time of different +// parts of the open simulation interface and the protobuf implementation. +// +// The regions of interests are the filling of the structure of a +// OSI GroundTruth message, the serialization and the parsing process using +// the native C++ interfaces of protobuf. +// +// \author Georg Seifert +// \version 0.1 +// \date 2021 +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, you can obtain one at http://mozilla.org/MPL/2.0/ +// + +#include +#include +#include +#include +#include +#include +#include +#include "clock.h" + +// \def ITERATIONS +// Default number of iterations of the benchmark +// +#define ITERATIONS (1000) + +// \def OBJECTS +// Default number of moving objects used to fill the structure +// +#define OBJECTS (10) + +int main(int argc, char** argv) +{ + uint64_t start, stop; + int c; + size_t i, num_object, num_object_max = OBJECTS, num_iterations_max = ITERATIONS; + size_t *ts_ser; + size_t *ts_deser; + size_t *ts_gen; + + std::mt19937 generator(time(0)); + std::uniform_real_distribution<> distribution(0.0, 1.0); + + while ((c = getopt(argc, argv, "o:i:h")) != -1) { + switch (c) { + case 'o': + num_object_max = atoi(optarg); + break; + case 'i': + num_iterations_max = atoi(optarg); + break; + case '?': + case 'h': + std::cout << "Argumente:" << std::endl << + "\t-o \tCount of the moving objects, default = " << OBJECTS << std::endl << + "\t-i \tIteration of the benchmark, default = " << ITERATIONS << std::endl; + return 1; + default: + break; + } + } + + std::cout << "Iterationen: " << num_iterations_max << + ", Moving Objects: " << num_object_max << std::endl; + + ts_ser = new size_t[num_iterations_max]; + ts_deser = new size_t[num_iterations_max]; + ts_gen = new size_t[num_iterations_max]; + + for(i = 0; i < num_iterations_max; i++) + { + osi3::GroundTruth gt_ser = osi3::GroundTruth(); + osi3::GroundTruth gt_deser = osi3::GroundTruth(); + std::string output; + + start = clock_get_ns(); + for(num_object = 0; num_object < num_object_max; num_object++) + { + osi3::MovingObject *mo = gt_ser.add_moving_object(); + mo->set_type(osi3::MovingObject_Type_TYPE_VEHICLE); + + osi3::MovingObject_VehicleClassification* vehicle_classification = new osi3::MovingObject_VehicleClassification(); + vehicle_classification->set_type(osi3::MovingObject_VehicleClassification_Type_TYPE_SMALL_CAR); + mo->set_allocated_vehicle_classification(vehicle_classification); + + osi3::Identifier * id = new osi3::Identifier(); + id->set_value(num_object); + mo->set_allocated_id(id); + + osi3::BaseMoving* base = new osi3::BaseMoving(); + + // length = 12.0m (StVZO 32, 3,1) + // width = 2.55 (StVZO 32, 3.1) + // height = 4.0 (STVZO 32, 2), + osi3::Dimension3d* dimension = new osi3::Dimension3d(); + dimension->set_length(12.0 * distribution(generator)); + dimension->set_width(2.55 * distribution(generator)); + dimension->set_height(4.0 * distribution(generator)); + base->set_allocated_dimension(dimension); + + // position: x, h, z (-512 -- 512) + osi3::Vector3d* position = new osi3::Vector3d(); + position->set_x(1024 * distribution(generator) - 512); + position->set_y(1024 * distribution(generator) - 512); + position->set_z(1024 * distribution(generator) - 512); + base->set_allocated_position(position); + + // roll, pitch, yaw (0 -- 2pi) + osi3::Orientation3d* orientation = new osi3::Orientation3d(); + orientation->set_roll(6.28 * distribution(generator)); + orientation->set_pitch(6.28 * distribution(generator)); + orientation->set_yaw(6.28 * distribution(generator)); + base->set_allocated_orientation(orientation); + + // velocity (-30 -- 100) + osi3::Vector3d* velocity = new osi3::Vector3d(); + velocity->set_x(130.0 * distribution(generator) - 20.0); + velocity->set_y(130.0 * distribution(generator) - 20.0); + velocity->set_z(130.0 * distribution(generator) - 20.0); + base->set_allocated_velocity(velocity); + + // acceleration (-12 -- 10), based on Pkw-Pkw-Unfälle + // https://doi.org/10.1007/978-3-8348-9974-3_12 + osi3::Vector3d* acceleration = new osi3::Vector3d(); + acceleration->set_x(22.0 * distribution(generator) - 12); + acceleration->set_y(22.0 * distribution(generator) - 12); + acceleration->set_z(22.0 * distribution(generator) - 12); + base->set_allocated_acceleration(acceleration); + + mo->set_allocated_base(base); + } + stop = clock_get_ns(); + ts_gen[i] = stop - start; + + start = clock_get_ns(); + gt_ser.SerializeToString(&output); + stop = clock_get_ns(); + ts_ser[i] = stop - start; + + start = clock_get_ns(); + gt_deser.ParseFromString(output); + stop = clock_get_ns(); + ts_deser[i] = stop - start; + } + + double min = std::numeric_limits::max(), max = 0, mean = 0, variance = 0, stddev = 0; + for(i = 0; i < num_iterations_max; i++) + { + min = (min > ts_gen[i]) ? ts_gen[i] : min; + max = (max < ts_gen[i]) ? ts_gen[i] : max; + mean += ts_gen[i]; + variance += ts_gen[i]*ts_gen[i]; + } + mean /= num_iterations_max; + variance = variance/num_iterations_max - mean*mean; + stddev = sqrt( variance ); + std::cout << "Fill:" << std::endl << + "\tmin = " << min << " ns" << std::endl << + "\tmax = " << max << " ns" << std::endl << + "\tmean = " << mean << " ns" << std::endl << + "\tstandard deviation = " << stddev << " ns" << std::endl; + + min = std::numeric_limits::max(), max = 0, mean=0, variance=0, stddev = 0; + for(i=0; i < num_iterations_max; i++) + { + min = (min > ts_ser[i]) ? ts_ser[i] : min; + max = (max < ts_ser[i]) ? ts_ser[i] : max; + mean += ts_ser[i]; + variance += ts_ser[i]*ts_ser[i]; + } + mean /= num_iterations_max; + variance= variance/num_iterations_max - mean*mean; + stddev = sqrt( variance ); + std::cout << "Serialize:" << std::endl << + "\tmin = " << min << " ns" << std::endl << + "\tmax = " << max << " ns" << std::endl << + "\tmean = " << mean << " ns" << std::endl << + "\tstandard deviation = " << stddev << " ns" << std::endl; + + min = std::numeric_limits::max(), max = 0, mean = 0, variance = 0, stddev = 0; + for(i = 0; i < num_iterations_max; i++) + { + min = (min > ts_deser[i]) ? ts_deser[i] : min; + max = (max < ts_deser[i]) ? ts_deser[i] : max; + mean += ts_deser[i]; + variance += ts_deser[i]*ts_deser[i]; + } + mean /= num_iterations_max; + variance = variance/num_iterations_max - mean*mean; + stddev = sqrt( variance ); + std::cout << "Parse:" << std::endl << + "\tmin = " << min << " ns" << std::endl << + "\tmax = " << max << " ns" << std::endl << + "\tmean = " << mean << " ns" << std::endl << + "\tstandard deviation = " << stddev << " ns" << std::endl; + + delete [] ts_ser; + delete [] ts_deser; + delete [] ts_gen; + return 0; +} diff --git a/gen_scenarios/performace/performance.py b/gen_scenarios/performace/performance.py new file mode 100644 index 000000000..3fe3dfa68 --- /dev/null +++ b/gen_scenarios/performace/performance.py @@ -0,0 +1,113 @@ +""" +\brief Simple performance evaluation example + +Simple test application, which measures the execution time of different +parts of the open simulation interface and the protobuf implementation. + +The regions of interests are the filling of the structure of a +OSI GroundTruth message, the serialization and the parsing process using +the native Python interfaces of protobuf. + +\author Georg Seifert +\version 0.1 +\date 2021 + +This Source Code Form is subject to the terms of the Mozilla +Public License v. 2.0. If a copy of the MPL was not distributed +with this file, you can obtain one at http://mozilla.org/MPL/2.0/ +""" + +import time +import random +import statistics +import argparse +import osi_groundtruth_pb2 +import osi_object_pb2 + +## Default number of iterations of the benchmark +ITERATIONS = 1000 + +## Default number of moving objects used to fill the structure +OBJECTS = 10 + +if __name__ == "__main__": + ts_ser = list() + ts_deser = list() + ts_gen = list() + + out = """{}: +\tmin = {} ns +\tmax = {} ns +\tmean = {} ns +\tstandard deviation = {} ns +""" + + parser = argparse.ArgumentParser() + parser.add_argument( + "--iterations", + "-i", + help="Iteration of the benchmark", + default=ITERATIONS, + type=int, + required=False, + ) + parser.add_argument( + "--moving_objects", + "-o", + help="Count of the moving objects", + default=OBJECTS, + type=int, + required=False, + ) + args = parser.parse_args() + iterations = args.iterations + objects = args.moving_objects + + print("Iterationen: {} , Moving Objects: {}".format(iterations, objects)) + + for i in range(iterations): + gt_ser = osi_groundtruth_pb2.GroundTruth() + gt_des = osi_groundtruth_pb2.GroundTruth() + + start = time.perf_counter_ns() + for object in range(objects): + mo = gt_ser.moving_object.add() + mo.id.value = object + mo.type = osi_object_pb2.MovingObject.TYPE_VEHICLE + mo.vehicle_classification.type = osi_object_pb2.MovingObject.VehicleClassification.TYPE_SMALL_CAR + mo.base.dimension.length = random.uniform(0, 12.0) + mo.base.dimension.width = random.uniform(0, 2.55) + mo.base.dimension.height = random.uniform(0, 4.0) + mo.base.position.x = random.uniform(-512, 512) + mo.base.position.y = random.uniform(-512, 512) + mo.base.position.z = random.uniform(-512, 512) + + mo.base.orientation.roll = random.uniform(0, 6.28) + mo.base.orientation.pitch = random.uniform(0, 6.28) + mo.base.orientation.yaw = random.uniform(0, 6.28) + mo.base.velocity.x = random.uniform(-20, 110) + mo.base.velocity.y = random.uniform(-20, 110) + mo.base.velocity.z = random.uniform(-20, 110) + + mo.base.acceleration.x = random.uniform(-12, 10) + mo.base.acceleration.y = random.uniform(-12, 10) + mo.base.acceleration.z = random.uniform(-12, 10) + stop = time.perf_counter_ns() + ts_gen.append(stop-start) + + start = time.perf_counter_ns() + data = gt_ser.SerializeToString() + stop = time.perf_counter_ns() + ts_ser.append(stop-start) + + start = time.perf_counter_ns() + gt_des.ParseFromString(data) + stop = time.perf_counter_ns() + ts_deser.append(stop-start) + + print(out.format("Fill", min(ts_gen), max(ts_gen), + statistics.mean(ts_gen), statistics.stdev(ts_gen))) + print(out.format("Serialize", min(ts_ser), max(ts_ser), + statistics.mean(ts_ser), statistics.stdev(ts_ser))) + print(out.format("Parse", min(ts_deser), max(ts_deser), + statistics.mean(ts_deser), statistics.stdev(ts_deser)))