diff --git a/src/c++/perf_analyzer/command_line_parser.cc b/src/c++/perf_analyzer/command_line_parser.cc index 38ec34b72..7398455cb 100644 --- a/src/c++/perf_analyzer/command_line_parser.cc +++ b/src/c++/perf_analyzer/command_line_parser.cc @@ -728,7 +728,7 @@ CLParser::Usage(const std::string& msg) "version 3, while modelB's version is unspecified", 18) << std::endl; - throw PerfAnalyzerException(GENERIC_ERROR); + exit(GENERIC_ERROR); } void @@ -813,719 +813,741 @@ CLParser::ParseCommandLine(int argc, char** argv) while ((opt = getopt_long( argc, argv, "vdazc:u:m:x:b:t:p:i:H:l:r:s:f:", long_options, NULL)) != -1) { - switch (opt) { - case 0: - params_->streaming = true; - break; - case 1: { - std::string max_threads{optarg}; - if (IsPositiveInteger(max_threads)) { - params_->max_threads = std::stoull(max_threads); - params_->max_threads_specified = true; - } else { - Usage("Failed to parse --max-threads. The value must be > 0."); + try { + switch (opt) { + case 0: + params_->streaming = true; + break; + case 1: { + std::string max_threads{optarg}; + if (std::stoi(max_threads) > 0) { + params_->max_threads = std::stoull(max_threads); + params_->max_threads_specified = true; + } else { + Usage("Failed to parse --max-threads. The value must be > 0."); + } + break; } - break; - } - case 2: { - std::string sequence_length{optarg}; - if (IsPositiveInteger(sequence_length)) { - params_->sequence_length = std::stoull(sequence_length); - } else { - std::cerr << "WARNING: The sequence length must be > 0. Perf " - "Analyzer will use default value if it is measuring " - "on sequence model." - << std::endl; + case 2: { + std::string sequence_length{optarg}; + if (std::stoi(sequence_length) > 0) { + params_->sequence_length = std::stoull(sequence_length); + } else { + std::cerr << "WARNING: The sequence length must be > 0. Perf " + "Analyzer will use default value if it is measuring " + "on sequence model." + << std::endl; + } + params_->sequence_length_specified = true; + break; } - params_->sequence_length_specified = true; - break; - } - case 3: - params_->percentile = std::atoi(optarg); - break; - case 4: - params_->user_data.push_back(optarg); - break; - case 5: { - std::string arg = optarg; - auto colon_pos = arg.rfind(":"); - if (colon_pos == std::string::npos) { - Usage( - "Failed to parse --shape. There must be a colon after input " - "name."); + case 3: + params_->percentile = std::atoi(optarg); + break; + case 4: + params_->user_data.push_back(optarg); + break; + case 5: { + std::string arg = optarg; + auto colon_pos = arg.rfind(":"); + if (colon_pos == std::string::npos) { + Usage( + "Failed to parse --shape. There must be a colon after input " + "name."); + } + std::string name = arg.substr(0, colon_pos); + std::string shape_str = arg.substr(name.size() + 1); + size_t pos = 0; + std::vector shape; + while (pos != std::string::npos) { + size_t comma_pos = shape_str.find(",", pos); + int64_t dim; + if (comma_pos == std::string::npos) { + dim = std::stoll(shape_str.substr(pos, comma_pos)); + pos = comma_pos; + } else { + dim = std::stoll(shape_str.substr(pos, comma_pos - pos)); + pos = comma_pos + 1; + } + if (dim <= 0) { + Usage( + "Failed to parse --shape. The dimensions of input tensor " + "must be > 0."); + } + shape.emplace_back(dim); + } + + params_->input_shapes[name] = shape; + break; } - std::string name = arg.substr(0, colon_pos); - std::string shape_str = arg.substr(name.size() + 1); - size_t pos = 0; - std::vector shape; - while (pos != std::string::npos) { - size_t comma_pos = shape_str.find(",", pos); - std::string dim; - if (comma_pos == std::string::npos) { - dim = shape_str.substr(pos, comma_pos); - pos = comma_pos; + case 6: + case 'p': { + std::string measurement_window_ms{optarg}; + if (std::stoi(measurement_window_ms) > 0) { + params_->measurement_window_ms = std::stoull(measurement_window_ms); } else { - dim = shape_str.substr(pos, comma_pos - pos); - pos = comma_pos + 1; - } - if (!IsPositiveInteger(dim)) { Usage( - "Failed to parse --shape. The values must be a valid " - "positive number."); + "Failed to parse --measurement-interval (-p). The value must " + "be > 0 msec."); } - shape.emplace_back(std::stoll(dim)); + break; } + case 7: { + params_->using_concurrency_range = true; + std::string arg = optarg; + size_t pos = 0; + int index = 0; + while (pos != std::string::npos) { + size_t colon_pos = arg.find(":", pos); + if (index > 2) { + Usage( + "Failed to parse --concurrency-range. The value does not " + "match ."); + } + int64_t val; + if (colon_pos == std::string::npos) { + val = std::stoull(arg.substr(pos, colon_pos)); + pos = colon_pos; + } else { + val = std::stoull(arg.substr(pos, colon_pos - pos)); + pos = colon_pos + 1; + } + switch (index) { + case 0: + params_->concurrency_range.start = val; + break; + case 1: + params_->concurrency_range.end = val; + break; + case 2: + params_->concurrency_range.step = val; + break; + } + index++; + } - params_->input_shapes[name] = shape; - break; - } - case 6: - case 'p': { - std::string measurement_window_ms{optarg}; - if (IsPositiveInteger(measurement_window_ms)) { - params_->measurement_window_ms = std::stoull(measurement_window_ms); - } else { - Usage( - "Failed to parse --measurement-interval (-p). The value must " - "be > 0 msec."); + break; } - break; - } - case 7: { - params_->using_concurrency_range = true; - std::string arg = optarg; - size_t pos = 0; - int index = 0; - while (pos != std::string::npos) { - size_t colon_pos = arg.find(":", pos); - if (index > 2) { + case 8: + case 'l': { + std::string latency_threshold_ms{optarg}; + if (std::stoi(latency_threshold_ms) == 0) { + params_->latency_threshold_ms = NO_LIMIT; + } else if (std::stoi(latency_threshold_ms) > 0) { + params_->latency_threshold_ms = std::stoull(latency_threshold_ms); + } else { Usage( - "Failed to parse --concurrency-range. The value does not " - "match ."); + "Failed to parse --latency-threshold (-l). The value must be " + ">= 0 msecs."); } - std::string val; - if (colon_pos == std::string::npos) { - val = arg.substr(pos, colon_pos); - pos = colon_pos; + break; + } + case 9: + case 's': { + std::string stability_threshold{optarg}; + if (std::stof(stability_threshold) >= 0.0) { + params_->stability_threshold = std::stof(optarg) / 100; } else { - val = arg.substr(pos, colon_pos - pos); - pos = colon_pos + 1; - } - - if (!IsNonNegativeInteger(val)) { Usage( - "Failed to parse --concurrency-range. The values must be a " - "valid non-negative number."); + "Failed to parse --stability-percentage (-s). The value must " + "be >= 0.0."); } - - switch (index) { - case 0: - params_->concurrency_range.start = std::stoull(val); - break; - case 1: - params_->concurrency_range.end = std::stoull(val); - break; - case 2: - params_->concurrency_range.step = std::stoull(val); - break; + break; + } + case 10: + case 'r': { + std::string max_trials{optarg}; + if (std::stoi(max_trials) > 0) { + params_->max_trials = std::stoull(max_trials); + } else { + Usage("Failed to parse --max-trials (-r). The value must be > 0."); } - index++; + break; } - - break; - } - case 8: - case 'l': { - std::string latency_threshold_ms{optarg}; - if (IsNonNegativeInteger(latency_threshold_ms)) { - uint64_t threshold{std::stoull(latency_threshold_ms)}; - params_->latency_threshold_ms = threshold > 0 ? threshold : NO_LIMIT; - } else { - Usage( - "Failed to parse --latency-threshold (-l). The value must be " - ">= 0 msecs."); + case 11: { + std::string arg = optarg; + // Check whether the argument is a directory + if (IsDirectory(arg) || IsFile(arg)) { + params_->user_data.push_back(optarg); + } else if (arg.compare("zero") == 0) { + params_->zero_input = true; + } else if (arg.compare("random") == 0) { + break; + } else { + Usage( + "Failed to parse --input-data. Unsupported type provided: '" + + std::string(optarg) + + "'. The available options are 'zero', 'random', path to a " + "directory, or a json file."); + } + break; } - break; - } - case 9: - case 's': { - std::string stability_threshold{optarg}; - if (IsNonNegativeFloat(stability_threshold)) { - params_->stability_threshold = std::stof(optarg) / 100; - } else { - Usage( - "Failed to parse --stability-percentage (-s). The value must " - "be >= 0.0."); + case 12: { + std::string string_length{optarg}; + if (std::stoi(string_length) > 0) { + params_->string_length = std::stoull(string_length); + } else { + Usage("Failed to parse --string-length. The value must be > 0"); + } + break; } - break; - } - case 10: - case 'r': { - std::string max_trials{optarg}; - if (IsPositiveInteger(max_trials)) { - params_->max_trials = std::stoull(max_trials); - } else { - Usage("Failed to parse --max-trials (-r). The value must be > 0."); + case 13: { + params_->string_data = optarg; + break; } - break; - } - case 11: { - std::string arg = optarg; - // Check whether the argument is a directory - if (IsDirectory(arg) || IsFile(arg)) { - params_->user_data.push_back(optarg); - } else if (arg.compare("zero") == 0) { - params_->zero_input = true; - } else if (arg.compare("random") == 0) { - break; - } else { - Usage( - "Failed to parse --input-data. Unsupported type provided: '" + - std::string(optarg) + - "'. The available options are 'zero', 'random', path to a " - "directory, or a json file."); + case 14: + case 'a': { + params_->async = true; + break; } - break; - } - case 12: { - std::string string_length{optarg}; - if (IsPositiveInteger(string_length)) { - params_->string_length = std::stoull(string_length); - } else { - Usage("Failed to parse --string-length. The value must be > 0"); + case 15: { + params_->forced_sync = true; + break; } - break; - } - case 13: { - params_->string_data = optarg; - break; - } - case 14: - case 'a': { - params_->async = true; - break; - } - case 15: { - params_->forced_sync = true; - break; - } - case 16: { - params_->using_request_rate_range = true; - std::string arg = optarg; - size_t pos = 0; - int index = 0; - while (pos != std::string::npos) { - size_t colon_pos = arg.find(":", pos); - if (index > 2) { - Usage( - "Failed to parse --request-rate-range. The value does not " - "match ."); + case 16: { + params_->using_request_rate_range = true; + std::string arg = optarg; + size_t pos = 0; + int index = 0; + while (pos != std::string::npos) { + size_t colon_pos = arg.find(":", pos); + if (index > 2) { + Usage( + "Failed to parse --request-rate-range. The value does not " + "match ."); + } + if (colon_pos == std::string::npos) { + params_->request_rate_range[index] = + std::stod(arg.substr(pos, colon_pos)); + pos = colon_pos; + } else { + params_->request_rate_range[index] = + std::stod(arg.substr(pos, colon_pos - pos)); + pos = colon_pos + 1; + index++; + } } - if (colon_pos == std::string::npos) { - params_->request_rate_range[index] = - std::stod(arg.substr(pos, colon_pos)); - pos = colon_pos; + + break; + } + case 17: { + std::string num_of_sequences{optarg}; + if (std::stoi(num_of_sequences) > 0) { + params_->num_of_sequences = std::stoul(num_of_sequences); } else { - params_->request_rate_range[index] = - std::stod(arg.substr(pos, colon_pos - pos)); - pos = colon_pos + 1; - index++; + Usage("Failed to parse --num-of-sequences. The value must be > 0."); } + break; } - - break; - } - case 17: { - std::string num_of_sequences{optarg}; - if (IsPositiveInteger(num_of_sequences)) { - params_->num_of_sequences = std::stoul(num_of_sequences); - } else { - Usage("Failed to parse --num-of-sequences. The value must be > 0."); + case 18: { + params_->search_mode = SearchMode::BINARY; + break; } - break; - } - case 18: { - params_->search_mode = SearchMode::BINARY; - break; - } - case 19: { - std::string arg = optarg; - if (arg.compare("poisson") == 0) { - params_->request_distribution = Distribution::POISSON; - } else if (arg.compare("constant") == 0) { - params_->request_distribution = Distribution::CONSTANT; - } else { - Usage( - "Failed to parse --request-distribution. Unsupported type " - "provided: '" + - std::string(optarg) + "'. Choices are 'posson' or 'constant'."); + case 19: { + std::string arg = optarg; + if (arg.compare("poisson") == 0) { + params_->request_distribution = Distribution::POISSON; + } else if (arg.compare("constant") == 0) { + params_->request_distribution = Distribution::CONSTANT; + } else { + Usage( + "Failed to parse --request-distribution. Unsupported type " + "provided: '" + + std::string(optarg) + "'. Choices are 'posson' or 'constant'."); + } + break; } - break; - } - case 20: { - std::string request_intervals_file{optarg}; - if (IsFile(request_intervals_file)) { - params_->request_intervals_file = request_intervals_file; - params_->using_custom_intervals = true; - } else { - Usage( - "Failed to parse --request-intervals. The value must be a " - "valid file path"); + case 20: { + std::string request_intervals_file{optarg}; + if (IsFile(request_intervals_file)) { + params_->request_intervals_file = request_intervals_file; + params_->using_custom_intervals = true; + } else { + Usage( + "Failed to parse --request-intervals. The value must be a " + "valid file path"); + } + break; } - break; - } - case 21: { - std::string arg = optarg; - if (arg.compare("system") == 0) { - params_->shared_memory_type = SharedMemoryType::SYSTEM_SHARED_MEMORY; - } else if (arg.compare("cuda") == 0) { + case 21: { + std::string arg = optarg; + if (arg.compare("system") == 0) { + params_->shared_memory_type = + SharedMemoryType::SYSTEM_SHARED_MEMORY; + } else if (arg.compare("cuda") == 0) { #ifdef TRITON_ENABLE_GPU - params_->shared_memory_type = SharedMemoryType::CUDA_SHARED_MEMORY; + params_->shared_memory_type = SharedMemoryType::CUDA_SHARED_MEMORY; #else - Usage( - "Cuda shared memory is not supported when " - "TRITON_ENABLE_GPU=0."); + Usage( + "Cuda shared memory is not supported when " + "TRITON_ENABLE_GPU=0."); #endif // TRITON_ENABLE_GPU - } else if (arg.compare("none") == 0) { - params_->shared_memory_type = SharedMemoryType::NO_SHARED_MEMORY; - } else { - Usage( - "Failed to parse --shared-memory. Unsupported type provided: " - "'" + - std::string(optarg) + - "'. The available options are 'system', 'cuda', or 'none'."); + } else if (arg.compare("none") == 0) { + params_->shared_memory_type = SharedMemoryType::NO_SHARED_MEMORY; + } else { + Usage( + "Failed to parse --shared-memory. Unsupported type provided: " + "'" + + std::string(optarg) + + "'. The available options are 'system', 'cuda', or 'none'."); + } + break; } - break; - } - case 22: { - std::string output_shm_size{optarg}; - if (IsNonNegativeInteger(output_shm_size)) { - params_->output_shm_size = std::stoull(output_shm_size); - } else { - Usage( - "Failed to parse --output-shared-memory-size. The value must " - "be >= 0."); + case 22: { + std::string output_shm_size{optarg}; + if (std::stoi(output_shm_size) >= 0) { + params_->output_shm_size = std::stoull(output_shm_size); + } else { + Usage( + "Failed to parse --output-shared-memory-size. The value must " + "be >= 0."); + } + break; } - break; - } - case 23: { - std::string arg = optarg; - if (arg.compare("triton") == 0) { - params_->kind = cb::TRITON; - } else if (arg.compare("tfserving") == 0) { - params_->kind = cb::TENSORFLOW_SERVING; - } else if (arg.compare("torchserve") == 0) { - params_->kind = cb::TORCHSERVE; - } else if (arg.compare("triton_c_api") == 0) { - params_->kind = cb::TRITON_C_API; - } else { - Usage( - "Failed to parse --service-kind. Unsupported type provided: '" + - std::string{optarg} + - "'. The available options are 'triton', 'tfserving', " - "'torchserve', or 'triton_c_api'."); + case 23: { + std::string arg = optarg; + if (arg.compare("triton") == 0) { + params_->kind = cb::TRITON; + } else if (arg.compare("tfserving") == 0) { + params_->kind = cb::TENSORFLOW_SERVING; + } else if (arg.compare("torchserve") == 0) { + params_->kind = cb::TORCHSERVE; + } else if (arg.compare("triton_c_api") == 0) { + params_->kind = cb::TRITON_C_API; + } else { + Usage( + "Failed to parse --service-kind. Unsupported type provided: '" + + std::string{optarg} + + "'. The available options are 'triton', 'tfserving', " + "'torchserve', or 'triton_c_api'."); + } + break; } - break; - } - case 24: - params_->model_signature_name = optarg; - break; - case 25: { - std::string arg = optarg; - if (arg.compare("none") == 0) { - params_->compression_algorithm = cb::COMPRESS_NONE; - } else if (arg.compare("deflate") == 0) { - params_->compression_algorithm = cb::COMPRESS_DEFLATE; - } else if (arg.compare("gzip") == 0) { - params_->compression_algorithm = cb::COMPRESS_GZIP; - } else { - Usage( - "Failed to parse --grpc-compression-algorithm. Unsupported " - "type provided: '" + - arg + - "'. The available options are 'gzip', 'deflate', or 'none'."); + case 24: + params_->model_signature_name = optarg; + break; + case 25: { + std::string arg = optarg; + if (arg.compare("none") == 0) { + params_->compression_algorithm = cb::COMPRESS_NONE; + } else if (arg.compare("deflate") == 0) { + params_->compression_algorithm = cb::COMPRESS_DEFLATE; + } else if (arg.compare("gzip") == 0) { + params_->compression_algorithm = cb::COMPRESS_GZIP; + } else { + Usage( + "Failed to parse --grpc-compression-algorithm. Unsupported " + "type provided: '" + + arg + + "'. The available options are 'gzip', 'deflate', or 'none'."); + } + params_->using_grpc_compression = true; + break; } - params_->using_grpc_compression = true; - break; - } - case 26: { - std::string arg = optarg; - if (arg.compare("time_windows") == 0) { - params_->measurement_mode = MeasurementMode::TIME_WINDOWS; - } else if (arg.compare("count_windows") == 0) { - params_->measurement_mode = MeasurementMode::COUNT_WINDOWS; - } else { - Usage( - "Failed to parse --measurement-mode. Unsupported type " - "provided: '" + - arg + - "'. The available options are 'time_windows' or " - "'count_windows'."); + case 26: { + std::string arg = optarg; + if (arg.compare("time_windows") == 0) { + params_->measurement_mode = MeasurementMode::TIME_WINDOWS; + } else if (arg.compare("count_windows") == 0) { + params_->measurement_mode = MeasurementMode::COUNT_WINDOWS; + } else { + Usage( + "Failed to parse --measurement-mode. Unsupported type " + "provided: '" + + arg + + "'. The available options are 'time_windows' or " + "'count_windows'."); + } + break; } - break; - } - case 27: { - std::string request_count{optarg}; - if (IsPositiveInteger(request_count)) { - params_->measurement_request_count = std::stoull(request_count); - } else { - Usage( - "Failed to parse --measurement-request-count. The value must " - "be > 0."); + case 27: { + std::string request_count{optarg}; + if (std::stoi(request_count) > 0) { + params_->measurement_request_count = std::stoull(request_count); + } else { + Usage( + "Failed to parse --measurement-request-count. The value must " + "be > 0."); + } + break; } - break; - } - case 28: { - params_->triton_server_path = optarg; - break; - } - case 29: { - params_->model_repository_path = optarg; - break; - } - case 30: { - std::string arg = optarg; - size_t pos = 0; - int index = 0; - while (pos != std::string::npos) { - size_t colon_pos = arg.find(":", pos); - if (index > 1) { + case 28: { + params_->triton_server_path = optarg; + break; + } + case 29: { + params_->model_repository_path = optarg; + break; + } + case 30: { + std::string arg = optarg; + int64_t start_id; + int64_t end_id; + size_t pos = 0; + int index = 0; + while (pos != std::string::npos) { + size_t colon_pos = arg.find(":", pos); + if (index > 1) { + Usage( + "Failed to parse --sequence-id-range. The value does not " + "match ."); + } + if (colon_pos == std::string::npos) { + std::string sequence_id{arg.substr(pos, colon_pos)}; + if (index == 0) { + start_id = std::stoi(sequence_id); + } else { + end_id = std::stoi(sequence_id); + } + pos = colon_pos; + } else { + std::string sequence_id{arg.substr(pos, colon_pos - pos)}; + start_id = std::stoi(sequence_id); + pos = colon_pos + 1; + index++; + } + } + + // Check for invalid inputs + if (start_id < 0 || end_id < 0) { Usage( - "Failed to parse --sequence-id-range. The value does not " - "match ."); + "Failed to parse --sequence-id-range. The range values must be " + ">= 0."); + } else if (start_id > end_id) { + Usage( + "Failed to parse --sequence-id-range. The 'end' value must be " + "greater than 'start' value."); } - std::string sequence_id; - if (colon_pos == std::string::npos) { - sequence_id = arg.substr(pos, colon_pos); - pos = colon_pos; + if (index == 0) { // Only start ID is given + params_->start_sequence_id = start_id; } else { - sequence_id = arg.substr(pos, colon_pos - pos); - pos = colon_pos + 1; + params_->start_sequence_id = start_id; + params_->sequence_id_range = end_id - start_id; } - - if (!IsNonNegativeInteger(sequence_id)) { + break; + } + case 31: { + params_->ssl_options.ssl_grpc_use_ssl = true; + break; + } + case 32: { + if (IsFile(optarg)) { + params_->ssl_options.ssl_grpc_root_certifications_file = optarg; + } else { Usage( - "Failed to parse --sequence-id-range. The range values must " - "be >= 0."); + "Failed to parse --ssl-grpc-root-certifications-file. The " + "value must be a valid file path."); } - - switch (index) { - case 0: - params_->start_sequence_id = std::stoull(sequence_id); - break; - case 1: - if (params_->start_sequence_id > std::stoull(sequence_id)) { - Usage( - "Failed to parse --sequence-id-range. The 'end' value " - "must be greater than 'start' value."); - } - params_->sequence_id_range = - std::stoull(sequence_id) - params_->start_sequence_id; - break; + break; + } + case 33: { + if (IsFile(optarg)) { + params_->ssl_options.ssl_grpc_private_key_file = optarg; + } else { + Usage( + "Failed to parse --ssl-grpc-private-key-file. The value must " + "be a valid file path."); } - index++; + break; } - - break; - } - case 31: { - params_->ssl_options.ssl_grpc_use_ssl = true; - break; - } - case 32: { - if (IsFile(optarg)) { - params_->ssl_options.ssl_grpc_root_certifications_file = optarg; - } else { - Usage( - "Failed to parse --ssl-grpc-root-certifications-file. The " - "value must be a valid file path."); + case 34: { + if (IsFile(optarg)) { + params_->ssl_options.ssl_grpc_certificate_chain_file = optarg; + } else { + Usage( + "Failed to parse --ssl-grpc-certificate-chain-file. The value " + "must be a valid file path."); + } + break; } - break; - } - case 33: { - if (IsFile(optarg)) { - params_->ssl_options.ssl_grpc_private_key_file = optarg; - } else { - Usage( - "Failed to parse --ssl-grpc-private-key-file. The value must " - "be a valid file path."); + case 35: { + if (std::atol(optarg) == 0 || std::atol(optarg) == 1) { + params_->ssl_options.ssl_https_verify_peer = std::atol(optarg); + } else { + Usage( + "Failed to parse --ssl-https-verify-peer. The value must be " + "either 0 or 1."); + } + break; } - break; - } - case 34: { - if (IsFile(optarg)) { - params_->ssl_options.ssl_grpc_certificate_chain_file = optarg; - } else { - Usage( - "Failed to parse --ssl-grpc-certificate-chain-file. The value " - "must be a valid file path."); + case 36: { + if (std::atol(optarg) == 0 || std::atol(optarg) == 1 || + std::atol(optarg) == 2) { + params_->ssl_options.ssl_https_verify_host = std::atol(optarg); + } else { + Usage( + "Failed to parse --ssl-https-verify-host. The value must be " + "either 0, 1, or 2."); + } + break; } - break; - } - case 35: { - if (std::atol(optarg) == 0 || std::atol(optarg) == 1) { - params_->ssl_options.ssl_https_verify_peer = std::atol(optarg); - } else { - Usage( - "Failed to parse --ssl-https-verify-peer. The value must be " - "either 0 or 1."); + case 37: { + if (IsFile(optarg)) { + params_->ssl_options.ssl_https_ca_certificates_file = optarg; + } else { + Usage( + "Failed to parse --ssl-https-ca-certificates-file. The value " + "must be a valid file path."); + } + break; } - break; - } - case 36: { - if (std::atol(optarg) == 0 || std::atol(optarg) == 1 || - std::atol(optarg) == 2) { - params_->ssl_options.ssl_https_verify_host = std::atol(optarg); - } else { - Usage( - "Failed to parse --ssl-https-verify-host. The value must be " - "either 0, 1, or 2."); + case 38: { + if (IsFile(optarg)) { + params_->ssl_options.ssl_https_client_certificate_file = optarg; + } else { + Usage( + "Failed to parse --ssl-https-client-certificate-file. The " + "value must be a valid file path."); + } + break; } - break; - } - case 37: { - if (IsFile(optarg)) { - params_->ssl_options.ssl_https_ca_certificates_file = optarg; - } else { - Usage( - "Failed to parse --ssl-https-ca-certificates-file. The value " - "must be a valid file path."); + case 39: { + if (std::string(optarg) == "PEM" || std::string(optarg) == "DER") { + params_->ssl_options.ssl_https_client_certificate_type = optarg; + } else { + Usage( + "Failed to parse --ssl-https-client-certificate-type. " + "Unsupported type provided: '" + + std::string{optarg} + + "'. The available options are 'PEM' or 'DER'."); + } + break; } - break; - } - case 38: { - if (IsFile(optarg)) { - params_->ssl_options.ssl_https_client_certificate_file = optarg; - } else { - Usage( - "Failed to parse --ssl-https-client-certificate-file. The " - "value must be a valid file path."); + case 40: { + if (IsFile(optarg)) { + params_->ssl_options.ssl_https_private_key_file = optarg; + } else { + Usage( + "Failed to parse --ssl-https-private-key-file. The value must " + "be a valid file path."); + } + break; } - break; - } - case 39: { - if (std::string(optarg) == "PEM" || std::string(optarg) == "DER") { - params_->ssl_options.ssl_https_client_certificate_type = optarg; - } else { - Usage( - "Failed to parse --ssl-https-client-certificate-type. " - "Unsupported type provided: '" + - std::string{optarg} + - "'. The available options are 'PEM' or 'DER'."); + case 41: { + if (std::string(optarg) == "PEM" || std::string(optarg) == "DER") { + params_->ssl_options.ssl_https_private_key_type = optarg; + } else { + Usage( + "Failed to parse --ssl-https-private-key-type. Unsupported " + "type provided: '" + + std::string{optarg} + + "'. The available options are 'PEM' or 'DER'."); + } + break; } - break; - } - case 40: { - if (IsFile(optarg)) { - params_->ssl_options.ssl_https_private_key_file = optarg; - } else { - Usage( - "Failed to parse --ssl-https-private-key-file. The value must " - "be a valid file path."); + case 42: { + params_->verbose_csv = true; + break; } - break; - } - case 41: { - if (std::string(optarg) == "PEM" || std::string(optarg) == "DER") { - params_->ssl_options.ssl_https_private_key_type = optarg; - } else { - Usage( - "Failed to parse --ssl-https-private-key-type. Unsupported " - "type provided: '" + - std::string{optarg} + - "'. The available options are 'PEM' or 'DER'."); + case 43: { + params_->enable_mpi = true; + break; } - break; - } - case 42: { - params_->verbose_csv = true; - break; - } - case 43: { - params_->enable_mpi = true; - break; - } - case 44: { - params_->trace_options["trace_file"] = {optarg}; - break; - } - case 45: { - std::string trace_level{optarg}; - if (trace_level == "OFF" || trace_level == "TIMESTAMPS" || - trace_level == "TENSORS") { - params_->trace_options["trace_level"] = {trace_level}; - } else { - Usage( - "Failed to parse --trace-level. Unsupported type provided: '" + - trace_level + - "'. The available options are 'OFF', 'TIMESTAMPS', or " - "'TENSORS'."); + case 44: { + params_->trace_options["trace_file"] = {optarg}; + break; } - break; - } - case 46: { - params_->trace_options["trace_rate"] = {optarg}; - break; - } - case 47: { - std::string trace_count{optarg}; - if (std::stoi(trace_count) >= -1) { - params_->trace_options["trace_count"] = {trace_count}; - } else { - Usage( - "Failed to parse --trace-count. The value must be >= 0 or set " - "to -1 (default)."); + case 45: { + std::string trace_level{optarg}; + if (trace_level == "OFF" || trace_level == "TIMESTAMPS" || + trace_level == "TENSORS") { + params_->trace_options["trace_level"] = {trace_level}; + } else { + Usage( + "Failed to parse --trace-level. Unsupported type provided: '" + + trace_level + + "'. The available options are 'OFF', 'TIMESTAMPS', or " + "'TENSORS'."); + } + break; } - break; - } - case 48: { - std::string log_frequency{optarg}; - if (IsNonNegativeInteger(log_frequency)) { - params_->trace_options["log_frequency"] = {log_frequency}; - } else { - Usage("Failed to parse --log-frequency. The value must be >= 0."); + case 46: { + params_->trace_options["trace_rate"] = {optarg}; + break; } - break; - } - case 49: { - params_->should_collect_metrics = true; - break; - } - case 50: { - params_->metrics_url = optarg; - params_->metrics_url_specified = true; - break; - } - case 51: { - std::string metrics_interval_ms{optarg}; - if (IsPositiveInteger(metrics_interval_ms)) { - params_->metrics_interval_ms = std::stoull(metrics_interval_ms); - params_->metrics_interval_ms_specified = true; - } else { - Usage( - "Failed to parse --metrics-interval. The value must be > 0 " - "msecs."); + case 47: { + std::string trace_count{optarg}; + if (std::stoi(trace_count) >= -1) { + params_->trace_options["trace_count"] = {trace_count}; + } else { + Usage( + "Failed to parse --trace-count. The value must be >= 0 or set " + "to -1 (default)."); + } + break; } - break; - } - case 52: { - params_->sequence_length_variation = std::stod(optarg); - break; - } - case 53: { - std::string arg = optarg; + case 48: { + std::string log_frequency{optarg}; + if (std::stoi(log_frequency) >= 0) { + params_->trace_options["log_frequency"] = {log_frequency}; + } else { + Usage("Failed to parse --log-frequency. The value must be >= 0."); + } + break; + } + case 49: { + params_->should_collect_metrics = true; + break; + } + case 50: { + params_->metrics_url = optarg; + params_->metrics_url_specified = true; + break; + } + case 51: { + std::string metrics_interval_ms{optarg}; + if (std::stoi(metrics_interval_ms) > 0) { + params_->metrics_interval_ms = std::stoull(metrics_interval_ms); + params_->metrics_interval_ms_specified = true; + } else { + Usage( + "Failed to parse --metrics-interval. The value must be > 0 " + "msecs."); + } + break; + } + case 52: { + params_->sequence_length_variation = std::stod(optarg); + break; + } + case 53: { + std::string arg = optarg; - // Remove all spaces in the string - arg.erase(std::remove_if(arg.begin(), arg.end(), ::isspace), arg.end()); + // Remove all spaces in the string + arg.erase( + std::remove_if(arg.begin(), arg.end(), ::isspace), arg.end()); - std::stringstream ss(arg); - while (ss.good()) { - std::string model_name; - std::string model_version{""}; - std::string tmp_model_name; + std::stringstream ss(arg); + while (ss.good()) { + std::string model_name; + std::string model_version{""}; + std::string tmp_model_name; - getline(ss, tmp_model_name, ','); + getline(ss, tmp_model_name, ','); - size_t colon_pos = tmp_model_name.find(":"); + size_t colon_pos = tmp_model_name.find(":"); - if (colon_pos == std::string::npos) { - model_name = tmp_model_name; - } else { - model_name = tmp_model_name.substr(0, colon_pos); - model_version = tmp_model_name.substr(colon_pos + 1); - } + if (colon_pos == std::string::npos) { + model_name = tmp_model_name; + } else { + model_name = tmp_model_name.substr(0, colon_pos); + model_version = tmp_model_name.substr(colon_pos + 1); + } - params_->bls_composing_models.push_back({model_name, model_version}); + params_->bls_composing_models.push_back( + {model_name, model_version}); + } + break; } - break; - } - case 54: { - params_->serial_sequences = true; - break; - } - case 55: { - cb::TensorFormat input_tensor_format{ParseTensorFormat(optarg)}; - if (input_tensor_format == cb::TensorFormat::UNKNOWN) { - Usage( - "Failed to parse --input-tensor-format. Unsupported type " - "provided: '" + - std::string{optarg} + - "'. The available options are 'binary' or 'json'."); + case 54: { + params_->serial_sequences = true; + break; } - params_->input_tensor_format = input_tensor_format; - break; - } - case 56: { - cb::TensorFormat output_tensor_format{ParseTensorFormat(optarg)}; - if (output_tensor_format == cb::TensorFormat::UNKNOWN) { - Usage( - "Failed to parse --output-tensor-format. Unsupported type " - "provided: '" + - std::string{optarg} + - "'. The available options are 'binary' or 'json'."); + case 55: { + cb::TensorFormat input_tensor_format{ParseTensorFormat(optarg)}; + if (input_tensor_format == cb::TensorFormat::UNKNOWN) { + Usage( + "Failed to parse --input-tensor-format. Unsupported type " + "provided: '" + + std::string{optarg} + + "'. The available options are 'binary' or 'json'."); + } + params_->input_tensor_format = input_tensor_format; + break; } - params_->output_tensor_format = output_tensor_format; - break; - } - case 57: { - PrintVersion(); - break; - } - case 'v': - params_->extra_verbose = params_->verbose; - params_->verbose = true; - break; - case 'z': - params_->zero_input = true; - break; - case 'd': - params_->using_old_options = true; - params_->dynamic_concurrency_mode = true; - break; - case 'u': - params_->url_specified = true; - params_->url = optarg; - break; - case 'm': - params_->model_name = optarg; - break; - case 'x': - params_->model_version = optarg; - break; - case 'b': { - std::string batch_size{optarg}; - if (IsPositiveInteger(batch_size)) { - params_->batch_size = std::stoull(batch_size); - params_->using_batch_size = true; - } else { - Usage("Failed to parse -b (batch size). The value must be > 0."); + case 56: { + cb::TensorFormat output_tensor_format{ParseTensorFormat(optarg)}; + if (output_tensor_format == cb::TensorFormat::UNKNOWN) { + Usage( + "Failed to parse --output-tensor-format. Unsupported type " + "provided: '" + + std::string{optarg} + + "'. The available options are 'binary' or 'json'."); + } + params_->output_tensor_format = output_tensor_format; + break; + } + case 57: { + PrintVersion(); + break; } - break; + case 58: { + std::string profile_export_file{optarg}; + if (IsFile(profile_export_file) || IsDirectory(profile_export_file)) { + Usage( + "Failed to parse --profile-export-file. Path must not already " + "exist."); + } + params_->profile_export_file = profile_export_file; + break; + } + case 'v': + params_->extra_verbose = params_->verbose; + params_->verbose = true; + break; + case 'z': + params_->zero_input = true; + break; + case 'd': + params_->using_old_options = true; + params_->dynamic_concurrency_mode = true; + break; + case 'u': + params_->url_specified = true; + params_->url = optarg; + break; + case 'm': + params_->model_name = optarg; + break; + case 'x': + params_->model_version = optarg; + break; + case 'b': { + std::string batch_size{optarg}; + if (std::stoi(batch_size) > 0) { + params_->batch_size = std::stoull(batch_size); + params_->using_batch_size = true; + } else { + Usage("Failed to parse -b (batch size). The value must be > 0."); + } + break; + } + case 't': + params_->using_old_options = true; + params_->concurrent_request_count = std::atoi(optarg); + break; + case 'i': + params_->protocol = ParseProtocol(optarg); + break; + case 'H': { + std::string arg = optarg; + std::string header = arg.substr(0, arg.find(":")); + (*params_->http_headers)[header] = arg.substr(header.size() + 1); + break; + } + case 'c': + params_->using_old_options = true; + params_->max_concurrency = std::atoi(optarg); + break; + case 'f': + params_->filename = optarg; + break; + case '?': + Usage(); + break; } - case 't': - params_->using_old_options = true; - params_->concurrent_request_count = std::atoi(optarg); - break; - case 'i': - params_->protocol = ParseProtocol(optarg); - break; - case 'H': { - std::string arg = optarg; - std::string header = arg.substr(0, arg.find(":")); - (*params_->http_headers)[header] = arg.substr(header.size() + 1); - break; + } + catch (const std::invalid_argument& ia) { + if (opt >= 'A') { // short options + Usage( + "Failed to parse -" + std::string{(char)opt} + + ". Invalid value provided: " + std::string{optarg}); + } else { + Usage( + "Failed to parse --" + std::string{long_options[opt].name} + + ". Invalid value provided: " + std::string{optarg}); } - case 'c': - params_->using_old_options = true; - params_->max_concurrency = std::atoi(optarg); - break; - case 'f': - params_->filename = optarg; - break; - case '?': - Usage(); - break; } } @@ -1748,4 +1770,5 @@ CLParser::VerifyOptions() } } } + }} // namespace triton::perfanalyzer diff --git a/src/c++/perf_analyzer/perf_utils.cc b/src/c++/perf_analyzer/perf_utils.cc index aac862a06..d6c0a8a37 100644 --- a/src/c++/perf_analyzer/perf_utils.cc +++ b/src/c++/perf_analyzer/perf_utils.cc @@ -388,45 +388,4 @@ ParseTensorFormat(const std::string& content_type_str) } } -bool -IsPositiveInteger(const std::string& str) -{ - if (str.empty()) { - return false; - } else if (str.size() == 1 && str[0] == '0') { - return false; - } - return std::all_of( - str.begin(), str.end(), - [](unsigned char c) { return std::isdigit(c); }) - ? true - : false; -} - -bool -IsNonNegativeInteger(const std::string& str) -{ - if (str.empty()) { - return false; - } else if (str.size() == 1 && str[0] == '0') { - return true; - } else if (str[0] == '-') { - return false; - } - return IsPositiveInteger(str); -} - -bool -IsNonNegativeFloat(const std::string& str) -{ - size_t pos{0}; - size_t dot_pos = str.find(".", pos); - if (dot_pos == std::string::npos) { - return IsNonNegativeInteger(str); - } else { - return IsNonNegativeInteger(str.substr(0, dot_pos)) && - IsNonNegativeInteger(str.substr(dot_pos + 1)); - } -} - }} // namespace triton::perfanalyzer diff --git a/src/c++/perf_analyzer/perf_utils.h b/src/c++/perf_analyzer/perf_utils.h index d5ea1ee26..7166936a9 100644 --- a/src/c++/perf_analyzer/perf_utils.h +++ b/src/c++/perf_analyzer/perf_utils.h @@ -137,13 +137,4 @@ std::function ScheduleDistribution( // Parse the HTTP tensor format cb::TensorFormat ParseTensorFormat(const std::string& tensor_format_str); -// Check if the given string is a valid positive integer. -bool IsPositiveInteger(const std::string& str); - -// Check if the given string is a valid non-negative integer. -bool IsNonNegativeInteger(const std::string& str); - -// Check if the given string is a valid non-negative floating point number. -bool IsNonNegativeFloat(const std::string& str); - }} // namespace triton::perfanalyzer diff --git a/src/c++/perf_analyzer/test_command_line_parser.cc b/src/c++/perf_analyzer/test_command_line_parser.cc index 431576d7d..86a5a9175 100644 --- a/src/c++/perf_analyzer/test_command_line_parser.cc +++ b/src/c++/perf_analyzer/test_command_line_parser.cc @@ -30,7 +30,6 @@ #include "command_line_parser.h" #include "doctest.h" -#include "perf_analyzer_exception.h" namespace triton { namespace perfanalyzer { @@ -178,6 +177,55 @@ CHECK_PARAMS(PAParamsPtr act, PAParamsPtr exp) CHECK_STRING(act->memory_type, exp->memory_type); } + +#define CHECK_INT_OPTION(option_name, exp_val, msg) \ + SUBCASE("valid value") \ + { \ + int argc = 5; \ + char* argv[argc] = {app_name, "-m", model_name, option_name, "2000"}; \ + CAPTURE(argv[3]); \ + CAPTURE(argv[4]); \ + \ + REQUIRE_NOTHROW(act = parser.Parse(argc, argv)); \ + CHECK(!parser.UsageCalled()); \ + CAPTURE(parser.GetUsageMessage()); \ + \ + exp_val = 2000; \ + CAPTURE(exp_val); \ + } \ + \ + SUBCASE("negative value") \ + { \ + int argc = 5; \ + char* argv[argc] = {app_name, "-m", model_name, option_name, "-2000"}; \ + REQUIRE_NOTHROW(act = parser.Parse(argc, argv)); \ + CHECK(parser.UsageCalled()); \ + CHECK_STRING("Usage Message", parser.GetUsageMessage(), msg); \ + } \ + \ + SUBCASE("floating point value") \ + { \ + int argc = 5; \ + char* argv[argc] = {app_name, "-m", model_name, option_name, "29.5"}; \ + \ + REQUIRE_NOTHROW(act = parser.Parse(argc, argv)); \ + CHECK(!parser.UsageCalled()); \ + \ + exp_val = 29; \ + } \ + \ + SUBCASE("missing value") \ + { \ + int argc = 4; \ + char* argv[argc] = {app_name, "-m", model_name, option_name}; \ + \ + opterr = 0; \ + REQUIRE_NOTHROW(act = parser.Parse(argc, argv)); \ + CHECK(parser.UsageCalled()); \ + CHECK_STRING("Usage Message", parser.GetUsageMessage(), ""); \ + } + + TEST_CASE("Testing PerfAnalyzerParameters") { PAParamsPtr params(new PerfAnalyzerParameters{}); @@ -291,7 +339,6 @@ class TestCLParser : public CLParser { { usage_called_ = true; usage_message_ = msg; - throw PerfAnalyzerException(msg, GENERIC_ERROR); } }; @@ -317,13 +364,14 @@ TEST_CASE("Testing Command Line Parser") int argc = 1; char* argv[argc] = {app_name}; + REQUIRE_NOTHROW(act = parser.Parse(argc, argv)); + REQUIRE(parser.UsageCalled()); + expected_msg = CreateUsageMessage("-m (model name)", "The value must be specified."); - CHECK_THROWS_WITH_AS( - act = parser.Parse(argc, argv), expected_msg.c_str(), - PerfAnalyzerException); + CHECK_STRING("Usage Message", parser.GetUsageMessage(), expected_msg); - check_params = false; + exp->model_name = ""; } SUBCASE("with min parameters") @@ -342,13 +390,14 @@ TEST_CASE("Testing Command Line Parser") int argc = 2; char* argv[argc] = {app_name, "--streaming"}; - expected_msg = - CreateUsageMessage("-m (model name)", "The value must be specified."); - CHECK_THROWS_WITH_AS( - act = parser.Parse(argc, argv), expected_msg.c_str(), - PerfAnalyzerException); + REQUIRE_NOTHROW(act = parser.Parse(argc, argv)); + REQUIRE(parser.UsageCalled()); + CHECK_STRING( + "Usage Message", parser.GetUsageMessage(), + "Streaming is only allowed with gRPC protocol."); - check_params = false; + exp->model_name = ""; + exp->streaming = true; } SUBCASE("with model") @@ -356,15 +405,17 @@ TEST_CASE("Testing Command Line Parser") int argc = 4; char* argv[argc] = {app_name, "-m", model_name, "--streaming"}; + REQUIRE_NOTHROW(act = parser.Parse(argc, argv)); + REQUIRE(parser.UsageCalled()); + // NOTE: This is not an informative error message, how do I specify a gRPC // protocol? Error output should list missing params. // - CHECK_THROWS_WITH_AS( - act = parser.Parse(argc, argv), - "Streaming is only allowed with gRPC protocol.", - PerfAnalyzerException); + CHECK_STRING( + "Usage Message", parser.GetUsageMessage(), + "Streaming is only allowed with gRPC protocol."); - check_params = false; + exp->streaming = true; } SUBCASE("with model last") @@ -372,12 +423,14 @@ TEST_CASE("Testing Command Line Parser") int argc = 4; char* argv[argc] = {app_name, "--streaming", "-m", model_name}; - CHECK_THROWS_WITH_AS( - act = parser.Parse(argc, argv), - "Streaming is only allowed with gRPC protocol.", - PerfAnalyzerException); + REQUIRE_NOTHROW(act = parser.Parse(argc, argv)); - check_params = false; + REQUIRE(parser.UsageCalled()); + CHECK_STRING( + "Usage Message", parser.GetUsageMessage(), + "Streaming is only allowed with gRPC protocol."); + + exp->streaming = true; } } @@ -414,27 +467,33 @@ TEST_CASE("Testing Command Line Parser") opterr = 0; // Disable error output for GetOpt library for this case - // Helpful error message handled by getopt_long - CHECK_THROWS_WITH_AS( - act = parser.Parse(argc, argv), "", PerfAnalyzerException); + REQUIRE_NOTHROW(act = parser.Parse(argc, argv)); + REQUIRE(parser.UsageCalled()); - check_params = false; + // NOTE: Empty message is not helpful + // + CHECK_STRING("Usage Message", parser.GetUsageMessage(), ""); + // BUG: Dumping string "option '--max-threads' requires an argument" + // directly to std::out, instead of through usage() + // } SUBCASE("bad value") { - int argc = 5; + int argc = 4; char* argv[argc] = {app_name, "-m", model_name, "--max-threads", "bad"}; opterr = 0; // Disable error output for GetOpt library for this case - expected_msg = - CreateUsageMessage("--max-threads", "The value must be > 0."); - CHECK_THROWS_WITH_AS( - act = parser.Parse(argc, argv), expected_msg.c_str(), - PerfAnalyzerException); + REQUIRE_NOTHROW(act = parser.Parse(argc, argv)); + REQUIRE(parser.UsageCalled()); - check_params = false; + // NOTE: Empty message is not helpful + // + CHECK_STRING("Usage Message", parser.GetUsageMessage(), ""); + // BUG: Dumping string "option '--max-threads' requires an argument" + // directly to std::out, instead of through usage() + // } } @@ -484,13 +543,14 @@ TEST_CASE("Testing Command Line Parser") char* argv[argc] = { app_name, "-m", model_name, "--sequence-length-variation", "-10"}; + REQUIRE_NOTHROW(act = parser.Parse(argc, argv)); + REQUIRE(parser.UsageCalled()); + expected_msg = CreateUsageMessage( "--sequence-length-variation", "The value must be >= 0.0."); - CHECK_THROWS_WITH_AS( - act = parser.Parse(argc, argv), expected_msg.c_str(), - PerfAnalyzerException); + CHECK_STRING("Usage Message", parser.GetUsageMessage(), expected_msg); - check_params = false; + exp->sequence_length_variation = -10.0; } } @@ -512,14 +572,15 @@ TEST_CASE("Testing Command Line Parser") int argc = 5; char* argv[argc] = {app_name, "-m", model_name, "--percentile", "225"}; + REQUIRE_NOTHROW(act = parser.Parse(argc, argv)); + CHECK(parser.UsageCalled()); + expected_msg = CreateUsageMessage( "--percentile", "The value must be -1 for not reporting or in range (0, 100)."); - CHECK_THROWS_WITH_AS( - act = parser.Parse(argc, argv), expected_msg.c_str(), - PerfAnalyzerException); + CHECK_STRING("Usage Message", parser.GetUsageMessage(), expected_msg); - check_params = false; + exp->percentile = 225; } SUBCASE("set to -1 - use average latency") @@ -534,7 +595,6 @@ TEST_CASE("Testing Command Line Parser") } } - // FIXME: Deprecated flag (TMA-1318) SUBCASE("Option : --data-directory") { SUBCASE("set to `/usr/data`") @@ -551,6 +611,10 @@ TEST_CASE("Testing Command Line Parser") SUBCASE("call twice") { + // QUESTION: Is this the expected behavior? There is not enough details in + // in the output. It is marked as deprecated, what does that mean? Is it + // used? + // int argc = 7; char* argv[argc] = {app_name, "-m", model_name, "--data-directory", "/usr/data", "--data-directory", @@ -596,13 +660,17 @@ TEST_CASE("Testing Command Line Parser") char* argv[argc] = { app_name, "-m", model_name, "--sequence-id-range", "53:67:92"}; + REQUIRE_NOTHROW(act = parser.Parse(argc, argv)); + CHECK(parser.UsageCalled()); + expected_msg = CreateUsageMessage( "--sequence-id-range", "The value does not match ."); - CHECK_THROWS_WITH_AS( - act = parser.Parse(argc, argv), expected_msg.c_str(), - PerfAnalyzerException); + CHECK_STRING("Usage Message", parser.GetUsageMessage(), expected_msg); - check_params = false; + // It will get the final 2 values + // + exp->start_sequence_id = 67; + exp->sequence_id_range = 25; } SUBCASE("Not a number") { @@ -610,11 +678,12 @@ TEST_CASE("Testing Command Line Parser") char* argv[argc] = { app_name, "-m", model_name, "--sequence-id-range", "BAD"}; + REQUIRE_NOTHROW(act = parser.Parse(argc, argv)); + CHECK(parser.UsageCalled()); + expected_msg = CreateUsageMessage( - "--sequence-id-range", "The range values must be >= 0."); - CHECK_THROWS_WITH_AS( - act = parser.Parse(argc, argv), expected_msg.c_str(), - PerfAnalyzerException); + "--sequence-id-range", "Invalid value provided: BAD"); + CHECK_STRING("Usage Message", parser.GetUsageMessage(), expected_msg); check_params = false; // Usage message called } @@ -624,57 +693,13 @@ TEST_CASE("Testing Command Line Parser") char* argv[argc] = { app_name, "-m", model_name, "--sequence-id-range", "53:BAD"}; - expected_msg = CreateUsageMessage( - "--sequence-id-range", "The range values must be >= 0."); - CHECK_THROWS_WITH_AS( - act = parser.Parse(argc, argv), expected_msg.c_str(), - PerfAnalyzerException); - - check_params = false; // Usage message called - } - - SUBCASE("Negative start value") - { - int argc = 5; - char* argv[argc] = { - app_name, "-m", model_name, "--sequence-id-range", "-12:34"}; - - expected_msg = CreateUsageMessage( - "--sequence-id-range", "The range values must be >= 0."); - CHECK_THROWS_WITH_AS( - act = parser.Parse(argc, argv), expected_msg.c_str(), - PerfAnalyzerException); - - check_params = false; // Usage message called - } - - SUBCASE("Negative end value") - { - int argc = 5; - char* argv[argc] = { - app_name, "-m", model_name, "--sequence-id-range", "12:-34"}; - - expected_msg = CreateUsageMessage( - "--sequence-id-range", "The range values must be >= 0."); - CHECK_THROWS_WITH_AS( - act = parser.Parse(argc, argv), expected_msg.c_str(), - PerfAnalyzerException); - - check_params = false; // Usage message called - } + REQUIRE_NOTHROW(act = parser.Parse(argc, argv)); + CHECK(parser.UsageCalled()); - SUBCASE("Start value greater than end value") - { - int argc = 5; - char* argv[argc] = { - app_name, "-m", model_name, "--sequence-id-range", "34:12"}; expected_msg = CreateUsageMessage( - "--sequence-id-range", - "The 'end' value must be greater than 'start' value."); - CHECK_THROWS_WITH_AS( - act = parser.Parse(argc, argv), expected_msg.c_str(), - PerfAnalyzerException); + "--sequence-id-range", "Invalid value provided: 53:BAD"); + CHECK_STRING("Usage Message", parser.GetUsageMessage(), expected_msg); check_params = false; // Usage message called } @@ -711,15 +736,10 @@ TEST_CASE("Testing Command Line Parser") char* argv[argc] = { app_name, "-m", model_name, "--input-tensor-format", "invalid"}; - expected_msg = CreateUsageMessage( - "--input-tensor-format", - "Unsupported type provided: 'invalid'. The available options are " - "'binary' or 'json'."); - CHECK_THROWS_WITH_AS( - act = parser.Parse(argc, argv), expected_msg.c_str(), - PerfAnalyzerException); + REQUIRE_NOTHROW(act = parser.Parse(argc, argv)); + CHECK(parser.UsageCalled()); - check_params = false; + exp->input_tensor_format = cb::TensorFormat::UNKNOWN; } } @@ -770,13 +790,15 @@ TEST_CASE("Testing Command Line Parser") char* argv[argc] = { app_name, "-m", model_name, "--shape", "input_name:-1,2,3"}; + REQUIRE_NOTHROW(act = parser.Parse(argc, argv)); + CHECK(parser.UsageCalled()); + expected_msg = CreateUsageMessage( - "--shape", "The values must be a valid positive number."); - CHECK_THROWS_WITH_AS( - act = parser.Parse(argc, argv), expected_msg.c_str(), - PerfAnalyzerException); + "--shape", "The dimensions of input tensor must be > 0."); + CHECK_STRING("Usage Message", parser.GetUsageMessage(), expected_msg); - check_params = false; + exp->input_shapes.emplace( + std::string("input_name"), std::vector{-1, 2, 3}); } SUBCASE("equals sign, not colon") @@ -785,11 +807,13 @@ TEST_CASE("Testing Command Line Parser") char* argv[argc] = { app_name, "-m", model_name, "--shape", "input_name=-1,2,3"}; - expected_msg = CreateUsageMessage( - "--shape", "There must be a colon after input name."); - CHECK_THROWS_WITH_AS( - act = parser.Parse(argc, argv), expected_msg.c_str(), - PerfAnalyzerException); + // BUG this should call usages with the message + // "failed to parse input shape. There must be a colon after input name + // + CHECK_THROWS_WITH( + act = parser.Parse(argc, argv), + "basic_string::substr: __pos (which is 18) > this->size() (which is " + "17)"); check_params = false; } @@ -799,11 +823,13 @@ TEST_CASE("Testing Command Line Parser") int argc = 5; char* argv[argc] = {app_name, "-m", model_name, "--shape", "input_name"}; - expected_msg = CreateUsageMessage( - "--shape", "There must be a colon after input name."); - CHECK_THROWS_WITH_AS( - act = parser.Parse(argc, argv), expected_msg.c_str(), - PerfAnalyzerException); + // BUG this should call usages with the message + // "failed to parse input shape. There must be a colon after input name + // + CHECK_THROWS_WITH( + act = parser.Parse(argc, argv), + "basic_string::substr: __pos (which is 11) > this->size() (which is " + "10)"); check_params = false; } @@ -814,11 +840,13 @@ TEST_CASE("Testing Command Line Parser") char* argv[argc] = { app_name, "-m", model_name, "--shape", "input_name1,2,3"}; - expected_msg = CreateUsageMessage( - "--shape", "There must be a colon after input name."); - CHECK_THROWS_WITH_AS( - act = parser.Parse(argc, argv), expected_msg.c_str(), - PerfAnalyzerException); + // BUG this should call usages with the message + // "failed to parse input shape. There must be a colon after input name + // + CHECK_THROWS_WITH( + act = parser.Parse(argc, argv), + "basic_string::substr: __pos (which is 16) > this->size() (which is " + "15)"); check_params = false; } @@ -829,11 +857,13 @@ TEST_CASE("Testing Command Line Parser") char* argv[argc] = { app_name, "-m", model_name, "--shape", "input_name:a,b,c"}; + REQUIRE_NOTHROW(act = parser.Parse(argc, argv)); + CHECK(parser.UsageCalled()); + + expected_msg = CreateUsageMessage( - "--shape", "The values must be a valid positive number."); - CHECK_THROWS_WITH_AS( - act = parser.Parse(argc, argv), expected_msg.c_str(), - PerfAnalyzerException); + "--shape", "Invalid value provided: input_name:a,b,c"); + CHECK_STRING("Usage Message", parser.GetUsageMessage(), expected_msg); check_params = false; // Usage message called } @@ -844,11 +874,13 @@ TEST_CASE("Testing Command Line Parser") char* argv[argc] = { app_name, "-m", model_name, "--shape", "input_name:[1,2,3]"}; + REQUIRE_NOTHROW(act = parser.Parse(argc, argv)); + CHECK(parser.UsageCalled()); + + expected_msg = CreateUsageMessage( - "--shape", "The values must be a valid positive number."); - CHECK_THROWS_WITH_AS( - act = parser.Parse(argc, argv), expected_msg.c_str(), - PerfAnalyzerException); + "--shape", "Invalid value provided: input_name:[1,2,3]"); + CHECK_STRING("Usage Message", parser.GetUsageMessage(), expected_msg); check_params = false; // Usage message called } @@ -896,13 +928,12 @@ TEST_CASE("Testing Command Line Parser") CAPTURE(argv[3]); + REQUIRE_NOTHROW(act = parser.Parse(argc, argv)); + CHECK(parser.UsageCalled()); + expected_msg = CreateUsageMessage( "--measurement-interval (-p)", "The value must be > 0 msec."); - CHECK_THROWS_WITH_AS( - act = parser.Parse(argc, argv), expected_msg.c_str(), - PerfAnalyzerException); - - check_params = false; + CHECK_STRING("Usage Message", parser.GetUsageMessage(), expected_msg); } SUBCASE("set to non-numeric value") @@ -913,19 +944,22 @@ TEST_CASE("Testing Command Line Parser") SUBCASE("Long form") { argv[3] = "--measurement-interval"; + expected_msg = CreateUsageMessage( + "--measurement-interval", "Invalid value provided: foobar"); } SUBCASE("Short form") { argv[3] = "-p"; + expected_msg = + CreateUsageMessage("-p", "Invalid value provided: foobar"); } CAPTURE(argv[3]); - expected_msg = CreateUsageMessage( - "--measurement-interval (-p)", "The value must be > 0 msec."); - CHECK_THROWS_WITH_AS( - act = parser.Parse(argc, argv), expected_msg.c_str(), - PerfAnalyzerException); + + REQUIRE_NOTHROW(act = parser.Parse(argc, argv)); + CHECK(parser.UsageCalled()); + CHECK_STRING("Usage Message", parser.GetUsageMessage(), expected_msg); check_params = false; // Usage message called } @@ -948,7 +982,7 @@ TEST_CASE("Testing Command Line Parser") exp->concurrency_range.step = 10; } - SUBCASE("only the start and end value") + SUBCASE("only two options") { int argc = 5; char* argv[argc] = { @@ -962,12 +996,14 @@ TEST_CASE("Testing Command Line Parser") exp->concurrency_range.end = 400; } - SUBCASE("only the start value") + SUBCASE("only one options") { int argc = 5; char* argv[argc] = { app_name, "-m", model_name, "--concurrency-range", "100"}; + // QUESTION: What does this mean? Why pass only one? + // REQUIRE_NOTHROW(act = parser.Parse(argc, argv)); CHECK(!parser.UsageCalled()); @@ -982,10 +1018,14 @@ TEST_CASE("Testing Command Line Parser") opterr = 0; // Disable error output for GetOpt library for this case - CHECK_THROWS_WITH_AS( - act = parser.Parse(argc, argv), "", PerfAnalyzerException); + REQUIRE_NOTHROW(act = parser.Parse(argc, argv)); + CHECK(parser.UsageCalled()); - check_params = false; + // BUG: Usage message does not contain error. Error statement + // "option '--concurrency-range' requires an argument" written directly + // to std::out + // + CHECK_STRING("Usage Message", parser.GetUsageMessage(), ""); } SUBCASE("too many options") @@ -994,13 +1034,17 @@ TEST_CASE("Testing Command Line Parser") char* argv[argc] = { app_name, "-m", model_name, "--concurrency-range", "200:100:25:10"}; + REQUIRE_NOTHROW(act = parser.Parse(argc, argv)); + CHECK(parser.UsageCalled()); + expected_msg = CreateUsageMessage( "--concurrency-range", "The value does not match ."); - CHECK_THROWS_WITH_AS( - act = parser.Parse(argc, argv), expected_msg.c_str(), - PerfAnalyzerException); + CHECK_STRING("Usage Message", parser.GetUsageMessage(), expected_msg); - check_params = false; + exp->using_concurrency_range = true; + exp->concurrency_range.start = 200; + exp->concurrency_range.end = 100; + exp->concurrency_range.step = 25; } SUBCASE("way too many options") @@ -1010,13 +1054,17 @@ TEST_CASE("Testing Command Line Parser") app_name, "-m", model_name, "--concurrency-range", "200:100:25:10:20:30"}; + REQUIRE_NOTHROW(act = parser.Parse(argc, argv)); + CHECK(parser.UsageCalled()); + expected_msg = CreateUsageMessage( "--concurrency-range", "The value does not match ."); - CHECK_THROWS_WITH_AS( - act = parser.Parse(argc, argv), expected_msg.c_str(), - PerfAnalyzerException); + CHECK_STRING("Usage Message", parser.GetUsageMessage(), expected_msg); - check_params = false; + exp->using_concurrency_range = true; + exp->concurrency_range.start = 200; + exp->concurrency_range.end = 100; + exp->concurrency_range.step = 25; } SUBCASE("wrong separator") @@ -1025,14 +1073,15 @@ TEST_CASE("Testing Command Line Parser") char* argv[argc] = { app_name, "-m", model_name, "--concurrency-range", "100,400,10"}; - expected_msg = CreateUsageMessage( - "--concurrency-range", - "The values must be a valid non-negative number."); - CHECK_THROWS_WITH_AS( - act = parser.Parse(argc, argv), expected_msg.c_str(), - PerfAnalyzerException); + REQUIRE_NOTHROW(act = parser.Parse(argc, argv)); + CHECK(!parser.UsageCalled()); - check_params = false; // Usage message called + // BUG: Should detect this and through an error. User will enter this and + // have no clue why the end and step sizes are not used correctly. + // + + exp->using_concurrency_range = true; + exp->concurrency_range.start = 100; } SUBCASE("bad start value") @@ -1041,14 +1090,14 @@ TEST_CASE("Testing Command Line Parser") char* argv[argc] = { app_name, "-m", model_name, "--concurrency-range", "bad:400:10"}; + REQUIRE_NOTHROW(act = parser.Parse(argc, argv)); + CHECK(parser.UsageCalled()); + expected_msg = CreateUsageMessage( - "--concurrency-range", - "The values must be a valid non-negative number."); - CHECK_THROWS_WITH_AS( - act = parser.Parse(argc, argv), expected_msg.c_str(), - PerfAnalyzerException); + "--concurrency-range", "Invalid value provided: bad:400:10"); + CHECK_STRING("Usage Message", parser.GetUsageMessage(), expected_msg); - check_params = false; + exp->using_concurrency_range = true; } SUBCASE("bad end value") @@ -1057,14 +1106,15 @@ TEST_CASE("Testing Command Line Parser") char* argv[argc] = { app_name, "-m", model_name, "--concurrency-range", "100:bad:10"}; + REQUIRE_NOTHROW(act = parser.Parse(argc, argv)); + CHECK(parser.UsageCalled()); + expected_msg = CreateUsageMessage( - "--concurrency-range", - "The values must be a valid non-negative number."); - CHECK_THROWS_WITH_AS( - act = parser.Parse(argc, argv), expected_msg.c_str(), - PerfAnalyzerException); + "--concurrency-range", "Invalid value provided: 100:bad:10"); + CHECK_STRING("Usage Message", parser.GetUsageMessage(), expected_msg); - check_params = false; + exp->using_concurrency_range = true; + exp->concurrency_range.start = 100; } SUBCASE("bad step value") @@ -1073,14 +1123,16 @@ TEST_CASE("Testing Command Line Parser") char* argv[argc] = { app_name, "-m", model_name, "--concurrency-range", "100:400:bad"}; + REQUIRE_NOTHROW(act = parser.Parse(argc, argv)); + CHECK(parser.UsageCalled()); + expected_msg = CreateUsageMessage( - "--concurrency-range", - "The values must be a valid non-negative number."); - CHECK_THROWS_WITH_AS( - act = parser.Parse(argc, argv), expected_msg.c_str(), - PerfAnalyzerException); + "--concurrency-range", "Invalid value provided: 100:400:bad"); + CHECK_STRING("Usage Message", parser.GetUsageMessage(), expected_msg); - check_params = false; + exp->using_concurrency_range = true; + exp->concurrency_range.start = 100; + exp->concurrency_range.end = 400; } SUBCASE("invalid condition - end and latency threshold are 0") @@ -1091,33 +1143,27 @@ TEST_CASE("Testing Command Line Parser") "100:0:25", "--latency-threshold", "0"}; - CHECK_THROWS_WITH_AS( - act = parser.Parse(argc, argv), + REQUIRE_NOTHROW(act = parser.Parse(argc, argv)); + CHECK(parser.UsageCalled()); + CHECK_STRING( + "Usage Message", parser.GetUsageMessage(), "The end of the search range and the latency limit can not be both 0 " - "(or 0.0) simultaneously", - PerfAnalyzerException); + "(or 0.0) simultaneously"); - check_params = false; + exp->using_concurrency_range = true; + exp->concurrency_range.start = 100; + exp->concurrency_range.end = 0; + exp->concurrency_range.step = 25; + exp->latency_threshold_ms = 0; } } SUBCASE("Option : --latency-threshold") { - SUBCASE("valid value") - { - int argc = 5; - char* argv[argc] = { - app_name, "-m", model_name, "--latency-threshold", "2000"}; - CAPTURE(argv[3]); - CAPTURE(argv[4]); - - REQUIRE_NOTHROW(act = parser.Parse(argc, argv)); - CHECK(!parser.UsageCalled()); - CAPTURE(parser.GetUsageMessage()); - - exp->latency_threshold_ms = 2000; - CAPTURE(exp->latency_threshold_ms); - } + expected_msg = CreateUsageMessage( + "--latency-threshold (-l)", "The value must be >= 0 msecs."); + CHECK_INT_OPTION( + "--latency-threshold", exp->latency_threshold_ms, expected_msg); SUBCASE("set to 0") { @@ -1128,33 +1174,6 @@ TEST_CASE("Testing Command Line Parser") REQUIRE_NOTHROW(act = parser.Parse(argc, argv)); CHECK(!parser.UsageCalled()); } - - SUBCASE("negative value") - { - int argc = 5; - char* argv[argc] = { - app_name, "-m", model_name, "--latency-threshold", "-2000"}; - - expected_msg = CreateUsageMessage( - "--latency-threshold (-l)", "The value must be >= 0 msecs."); - CHECK_THROWS_WITH_AS( - act = parser.Parse(argc, argv), expected_msg.c_str(), - PerfAnalyzerException); - - check_params = false; - } - - SUBCASE("missing value") - { - int argc = 4; - char* argv[argc] = {app_name, "-m", model_name, "--latency-threshold"}; - - opterr = 0; - CHECK_THROWS_WITH_AS( - act = parser.Parse(argc, argv), "", PerfAnalyzerException); - - check_params = false; - } } SUBCASE("Option : --stability-percentage") @@ -1187,13 +1206,12 @@ TEST_CASE("Testing Command Line Parser") char* argv[argc] = { app_name, "-m", model_name, "--stability-percentage", "-20"}; + REQUIRE_NOTHROW(act = parser.Parse(argc, argv)); + CHECK(parser.UsageCalled()); + expected_msg = CreateUsageMessage( "--stability-percentage (-s)", "The value must be >= 0.0."); - CHECK_THROWS_WITH_AS( - act = parser.Parse(argc, argv), expected_msg.c_str(), - PerfAnalyzerException); - - check_params = false; + CHECK_STRING("Usage Message", parser.GetUsageMessage(), expected_msg); } SUBCASE("floating point value") @@ -1214,10 +1232,9 @@ TEST_CASE("Testing Command Line Parser") char* argv[argc] = {app_name, "-m", model_name, "--stability-percentage"}; opterr = 0; - CHECK_THROWS_WITH_AS( - act = parser.Parse(argc, argv), "", PerfAnalyzerException); - - check_params = false; + REQUIRE_NOTHROW(act = parser.Parse(argc, argv)); + CHECK(parser.UsageCalled()); + CHECK_STRING("Usage Message", parser.GetUsageMessage(), ""); } } @@ -1225,56 +1242,17 @@ TEST_CASE("Testing Command Line Parser") { expected_msg = CreateUsageMessage("--max-trials (-r)", "The value must be > 0."); - - SUBCASE("valid value") - { - int argc = 5; - char* argv[argc] = {app_name, "-m", model_name, "--max-trials", "2000"}; - CAPTURE(argv[3]); - CAPTURE(argv[4]); - - REQUIRE_NOTHROW(act = parser.Parse(argc, argv)); - CHECK(!parser.UsageCalled()); - CAPTURE(parser.GetUsageMessage()); - - exp->max_trials = 2000; - CAPTURE(exp->max_trials); - } + CHECK_INT_OPTION("--max-trials", exp->max_trials, expected_msg); SUBCASE("set to 0") { int argc = 5; char* argv[argc] = {app_name, "-m", model_name, "--max-trials", "0"}; - CHECK_THROWS_WITH_AS( - act = parser.Parse(argc, argv), expected_msg.c_str(), - PerfAnalyzerException); - - check_params = false; - } - - SUBCASE("negative value") - { - int argc = 5; - char* argv[argc] = {app_name, "-m", model_name, "--max-trials", "-2000"}; - - CHECK_THROWS_WITH_AS( - act = parser.Parse(argc, argv), expected_msg.c_str(), - PerfAnalyzerException); - - check_params = false; - } - - SUBCASE("missing value") - { - int argc = 4; - char* argv[argc] = {app_name, "-m", model_name, "--max-trials"}; - - opterr = 0; - CHECK_THROWS_WITH_AS( - act = parser.Parse(argc, argv), "", PerfAnalyzerException); + REQUIRE_NOTHROW(act = parser.Parse(argc, argv)); + CHECK(parser.UsageCalled()); - check_params = false; + CHECK_STRING("Usage Message", parser.GetUsageMessage(), expected_msg); } } @@ -1286,14 +1264,17 @@ TEST_CASE("Testing Command Line Parser") char* argv[argc] = { app_name, "-m", model_name, "--collect-metrics", "--service-kind", "tfserving", "-i", "grpc"}; - - CHECK_THROWS_WITH_AS( - act = parser.Parse(argc, argv), + REQUIRE_NOTHROW(act = parser.Parse(argc, argv)); + CHECK(parser.UsageCalled()); + CHECK_STRING( + "Usage Message", parser.GetUsageMessage(), "Server-side metric collection is only supported with Triton client " - "backend.", - PerfAnalyzerException); + "backend."); - check_params = false; + exp->kind = cb::BackendKind::TENSORFLOW_SERVING; + exp->url = "localhost:8500"; + exp->batch_size = 0; + exp->protocol = cb::ProtocolType::GRPC; } } @@ -1304,12 +1285,11 @@ TEST_CASE("Testing Command Line Parser") char* argv[argc] = { app_name, "-m", model_name, "--metrics-url", "localhost:8002/metrics"}; - CHECK_THROWS_WITH_AS( - act = parser.Parse(argc, argv), - "Must specify --collect-metrics when using the --metrics-url option.", - PerfAnalyzerException); - - check_params = false; + REQUIRE_NOTHROW(act = parser.Parse(argc, argv)); + CHECK(parser.UsageCalled()); + CHECK_STRING( + "Usage Message", parser.GetUsageMessage(), + "Must specify --collect-metrics when using the --metrics-url option."); } SUBCASE("Option : --metrics-interval") @@ -1320,13 +1300,12 @@ TEST_CASE("Testing Command Line Parser") char* argv[argc] = { app_name, "-m", model_name, "--metrics-interval", "1000"}; - CHECK_THROWS_WITH_AS( - act = parser.Parse(argc, argv), + REQUIRE_NOTHROW(act = parser.Parse(argc, argv)); + CHECK(parser.UsageCalled()); + CHECK_STRING( + "Usage Message", parser.GetUsageMessage(), "Must specify --collect-metrics when using the --metrics-interval " - "option.", - PerfAnalyzerException); - - check_params = false; + "option."); } SUBCASE("metrics interval 0") @@ -1336,13 +1315,14 @@ TEST_CASE("Testing Command Line Parser") app_name, "-m", model_name, "--collect-metrics", "--metrics-interval", "0"}; + REQUIRE_NOTHROW(act = parser.Parse(argc, argv)); + CHECK(parser.UsageCalled()); + expected_msg = CreateUsageMessage( "--metrics-interval", "The value must be > 0 msecs."); - CHECK_THROWS_WITH_AS( - act = parser.Parse(argc, argv), expected_msg.c_str(), - PerfAnalyzerException); + CHECK_STRING("Usage Message", parser.GetUsageMessage(), expected_msg); - check_params = false; + exp->metrics_interval_ms = 0; } } diff --git a/src/c++/perf_analyzer/test_perf_utils.cc b/src/c++/perf_analyzer/test_perf_utils.cc index 38456f796..34a08a108 100644 --- a/src/c++/perf_analyzer/test_perf_utils.cc +++ b/src/c++/perf_analyzer/test_perf_utils.cc @@ -370,56 +370,5 @@ TEST_CASE("perf_utils: TensorToRegionName") CHECK(TensorToRegionName("") == ""); } -TEST_CASE("perf_utils: Test string input numbers") -{ - std::string pos{"123"}; - std::string neg{"-123"}; - std::string zero{"0"}; - std::string not_integer{"helloworld"}; - std::string almost_integer{"123hello"}; - std::string empty{""}; - - SUBCASE("IsPositiveInteger") - { - CHECK(IsPositiveInteger(pos) == true); - CHECK(IsPositiveInteger(neg) == false); - CHECK(IsPositiveInteger(zero) == false); - CHECK(IsPositiveInteger(not_integer) == false); - CHECK(IsPositiveInteger(almost_integer) == false); - CHECK(IsPositiveInteger(empty) == false); - } - - SUBCASE("IsNonNegativeInteger") - { - CHECK(IsNonNegativeInteger(pos) == true); - CHECK(IsNonNegativeInteger(neg) == false); - CHECK(IsNonNegativeInteger(zero) == true); - CHECK(IsNonNegativeInteger(not_integer) == false); - CHECK(IsNonNegativeInteger(almost_integer) == false); - CHECK(IsNonNegativeInteger(empty) == false); - } - - SUBCASE("IsNonNegativeFloat") - { - std::string pos_float{"123.456"}; - std::string neg_float{"-123.456"}; - std::string zero_float{"0.0"}; - std::string fraction{"0.01"}; - std::string almost_float{"123.01hello"}; - - CHECK(IsNonNegativeFloat(pos_float) == true); - CHECK(IsNonNegativeFloat(neg_float) == false); - CHECK(IsNonNegativeFloat(zero_float) == true); - CHECK(IsNonNegativeFloat(fraction) == true); - CHECK(IsNonNegativeFloat(pos) == true); - CHECK(IsNonNegativeFloat(neg) == false); - CHECK(IsNonNegativeFloat(zero) == true); - CHECK(IsNonNegativeFloat(not_integer) == false); - CHECK(IsNonNegativeFloat(almost_integer) == false); - CHECK(IsNonNegativeFloat(almost_float) == false); - CHECK(IsNonNegativeFloat(empty) == false); - } -} - }} // namespace triton::perfanalyzer